如何在使用嵌套上下文时自动设置Core Data关系

我正在努力想出一个体面的解决scheme,以解决在Core Data中使用嵌套托pipe对象上下文时出现的问题。 采取一个模型,有两个enite,个人和名称,其中每个人有一个与名称的一对一的关系,名称的人际关系是不可选的。 以前,在Person的-awakeFromInsert方法中,我会自动为新Person创build一个Name实体:

 - (void)awakeFromInsert { [super awakeFromInsert]; NSManagedObjectContext *context = [self managedObjectContext]; self.name = [NSEntityDescription insertNewObjectForEntityForName:@"Name" inManagedObjectContext:context]; } 

这在单个非嵌套的托pipe对象上下文中工作得很好。 但是,如果上下文具有父上下文,则在保存子上下文时,会在父上下文中创build一个新的Person对象,并在复制原始Person的属性和关系之前再次调用此对象上的-awakeFromInsert 。 所以,创build另一个Name对象,然后在复制现有名称关系时“断开”。 保存失败,因为浮动名称的现在无人关系validation失败。 这个问题在这里以及在其他地方描述。

到目前为止,我一直无法解决这个问题。 在getter方法中懒于创build关系实际上会导致同样的问题,因为在父上下文中创build新Person时,内部Core Data机制会调用getter。

我唯一可以想到的是放弃自动关系生成,并且总是在创buildPerson的控制器类中或者在便捷方法(例如+[Person insertNewPersonInManagedObjectContext:] )中明确地创build关系,我的代码,并且总是显式创build一个新的Person对象的方法。 也许这是最好的解决scheme,但我宁愿不必如此严格,只允许使用单个方法来创build托pipe对象,而其他创build方法,我无法控制和使用我不能容易检查/排除,存在。 首先,这将意味着多个NSArrayController子类来自定义创build托pipe对象的方式。

有没有其他人遇到这个问题提出了一个优雅的解决scheme,允许一个NSManagedObject创build/插入时自动创build一个关系对象?

首先想到的是,尽pipeName的人际关系是非可选的,但是你并没有说Personname关系也是非可选的。 可以创build一个没有NamePerson ,用你的代码处理,然后在你实际需要的时候再创build一个Name

如果不是的话,一个简单的方法就是在创build一个Name之前检查你是否在根上下文中:

 - (void)awakeFromInsert { [super awakeFromInsert]; NSManagedObjectContext *context = [self managedObjectContext]; if ([context parentContext] != nil) { self.name = [NSEntityDescription insertNewObjectForEntityForName:@"Name" inManagedObjectContext:context]; } } 

但是,只有当你总是在子上下文中创build新的实例,并且永远不会将上下文嵌套到一个以上的层次时才有效。

我可能会做的是创build一个像insertNewPersonInManagedObjectContext:的方法insertNewPersonInManagedObjectContext:你描述的。 然后用下面的东西来补充它,以处理任何情况下为你创build的实例(即数组控制器):

 - (void)willSave { if ([self name] == nil) { NSManagedObjectContext *context = [self managedObjectContext]; Name *name = [NSEntityDescription insertNewObjectForEntityForName:@"Name" inManagedObjectContext:context]; [self setName:name]; } } 

…当然不要打扰自定义awakeFromInsert

我最终用便捷方法解决scheme。 我的应用程序中的所有NSManagedObject子类都有一个+insertInManagedObjectContext:方法。 创build这些对象的实例(在我自己的代码中) 总是使用该方法完成的。 在这个方法里面,我这样做:

 + (instancetype)insertInManagedObjectContext:(NSManagedObjectContext *)moc { MyManagedObject *result = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntityName" inManagedObjectContext:moc] [result awakeFromCreation]; return result; } - (void)awakeFromCreation { // Do here what used to be done in -awakeFromInsert. // Set up default relationships, etc. } 

至于NSArrayController问题,解决这个问题根本不算什么。 我简单地创build了NSArrayController的子类,overrode -newObject ,并在我的应用程序中使用该子类的所有相关NSArrayController:

 @implementation ORSManagedObjectsArrayController - (id)newObject { NSManagedObjectContext *moc = [self managedObjectContext]; NSEntityDescription *entity = [NSEntityDescription entityForName:[self entityName] inManagedObjectContext:moc]; if (!entity) return nil; Class class = NSClassFromString([entity managedObjectClassName]); return [class insertInManagedObjectContext:moc]; } @end