我几天前遇到这个问题(link )。在简单的例子中将简短地说明这一点。我有公司实体,其中包含许多实体员工和一个实体CEO(继承自员工)。
完成我的数据模型后,我向该公司增加了5名员工,我将首席执行官分配到该公司。在测试时,我打电话给company.employees,预计会有5名员工,但结果与我的预期不一样,我也将CEO作为我的员工之一。
从这个事件中感到震惊我开始搜索关于apple doc的解释,我看到两篇相关的文章Fetching and Entity Inheritance说
如果您定义实体继承层次结构(请参阅“实体 继承“),指定一个超级实体作为一个实体 获取请求,请求返回所有匹配的实例 超实体和子实体。
关系指定实体或父实体 目的地的物体。这可以与实体相同 来源(反身关系)。关系不一定是 同质。如果Employee实体有两个子实体,比如Manager 和Flunky,然后给定部门的员工可能组成 员工(假设员工不是抽象实体),经理, Flunkies,或其任何组合。
这种行为是否正常?如果是的话,我可以高枕无忧地重新设计我的问题(here)。如果有人能指出我更详细地解释这种情况的位置,那就太棒了。
谢谢
更新主题并添加重新执行步骤 现在我认为这可能是某种SDK错误。这是我的重复步骤 制作3个实体
Family
- int generation
- parents as to-may relation to Parent and family as inverse
- child as to-one relation to Child and family as inverse
Parent
- String name
- family to-one relation to Family
Child : Parent
这是我的代码
Family *fam;
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Family" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSArray *meters = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
if ([meters count] > 0) {
NSLog(@"found");
fam = [meters lastObject];
fam.generation = [NSNumber numberWithInt:[fam.generation intValue] + 1];
} else {
NSLog(@"new");
fam = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:self.managedObjectContext];
fam.generation = [NSNumber numberWithInt:1];
[self saveContext];
};
NSLog(@"There are %d paren", [fam.parents count]);
for (Parent *p in fam.parents) {
NSLog(@"name : %@", p.name);
}
Child *child;
if (!fam.child) {
child = [NSEntityDescription insertNewObjectForEntityForName:
[[NSEntityDescription entityForName:@"Child" inManagedObjectContext:self.managedObjectContext] name]
inManagedObjectContext:self.managedObjectContext];
fam.child = child;
}
fam.child.name = [NSString stringWithFormat:@"child number %d", [fam.generation intValue]];
NSLog(@"There are %d parent after adding one child", [fam.parents count]);
Parent *parent = [NSEntityDescription insertNewObjectForEntityForName:
[[NSEntityDescription entityForName:@"Parent" inManagedObjectContext:self.managedObjectContext] name]
inManagedObjectContext:self.managedObjectContext];
parent.name = [NSString stringWithFormat:@"parent number %d", [fam.generation intValue]];
[fam addParentsObject:parent];
NSLog(@"There are %d parent after add parent", [fam.parents count]);
for (Parent *p in fam.parents) {
NSLog(@"name : %@", p.name);
}
[self saveContext];
简而言之,我创建了一个家庭,并为这个家庭添加了一个孩子和一个父母,并打印出一些输出 在第一次运行中我得到了这个结果
2011-08-27 19:06:28.271 child[2015:207] new
2011-08-27 19:06:28.276 child[2015:207] There are 0 paren
2011-08-27 19:06:28.278 child[2015:207] There are 0 parent after adding one child
2011-08-27 19:06:28.279 child[2015:207] There are 1 parent after add parent
2011-08-27 19:06:28.280 child[2015:207] name : parent number 1
这是我的预期,然后我再次重新运行应用程序,这就是奇怪的事情发生了
2011-08-27 19:08:12.383 child[2035:207] found
2011-08-27 19:08:12.386 child[2035:207] There are 2 paren
2011-08-27 19:08:12.387 child[2035:207] name : parent number 1
2011-08-27 19:08:12.388 child[2035:207] name : child number 1
2011-08-27 19:08:12.389 child[2035:207] There are 2 parent after adding one child
2011-08-27 19:08:12.390 child[2035:207] There are 3 parent after add parent
2011-08-27 19:08:12.390 child[2035:207] name : parent number 1
2011-08-27 19:08:12.391 child[2035:207] name : parent number 2
2011-08-27 19:08:12.391 child[2035:207] name : child number 2
没有理由将子实体包含在fam.parents属性中。
答案 0 :(得分:0)
我认为你引用的第一件事就是你的问题。引用company.employees不是获取请求。
我怀疑它可能与反向关系有关。您是否在Employee上有一家关系公司,这与Company.employees相反?
然后当您将首席执行官分配到这样的公司时:
ceo.company = company;
然后在核心数据的幕后说,首席执行官是一名员工。将公司分配给员工时,请指定反向关系。将员工分配给公司的员工关系。它会自动生成以下代码的效果:
[company addEmployeesObject:ceo];
在我看来,反向关系在核心数据中很烦人。很多时候你的代码不需要它们,但它们几乎都是Core Data内部工作所要求的。如果结果证明这是您的问题,请告诉我,我可能会建议一个解决方法。
编辑:
您的父子示例第二次运行的行为就是我所期望的。
您指定
fam.child = child
Family.child的反向关系是Child.family,因此Core Data会生成赋值
child.family = fam
Child继承自Parent。 Parent.family的反向关系是Family.parent,因此Child.family的反向关系也是Family.parent。因此,Core Data会生成插入
[fam addParentsObject:child]
我没想到的是第一次运行的结果。如果将子项添加到父项,则应将其添加到托管对象上下文中,并且应立即可见。
你可以把它称为一个错误,但无论如何,错误行为实际上就是你想要的。你不想要的是在第二次运行中发生的事情,这实际上是“正确的”行为。实际上,行为确实是未定义的,因为您构建了一个不一致的数据模型。你有效地说过
A.b的倒数是B.a
B.a的倒数是A.c
反转并不是真正的反转。我认为你在建造时会发现一个警告。
好的,那么如何解决原来的问题?
我的第一个建议是你不要让CEO继承员工。但如果你有理由为什么要这样做,那么这就是如何让它发挥作用。
核心数据要求您定义反转和反转以遵循Core Data的规则。如果您不想遵循Core Data的规则,则根据Core Data的规则定义反转,但不要使用它们。所以定义你的数据模型如下:
Company
employees: (to-many) Employee - inverse isEmployeeOf
ceo: (to-one) CEO - inverse isCEOOf
// unused
people: (to-many) Employee - inverse company
Employee
company: (to-one) Company - inverse people
// unused
isEmployeeOf: (to-one) Company - inverse employees
CEO : Employee
// unused
isCEOOf: (to-one) Company - inverse ceo
现在创建一个公司myCompany,其中包含一名员工mrEmployee和一名CEO mrCEO。您可能需要手动设置更多内容,因为您使用的属性没有定义反转。
[myCompany addEmployeesObject:mrEmployee];
mrEmployee.company = myCompany; // not automatic, because not official inverse
myCompany.ceo = mrCEO;
mrCEO.company = myCompany;
他们将拥有以下关系:
myCompany
employees - {mrEmployee}
ceo - mrCEO
people - {mrEmployee, mrCEO}
mrEmployee
company - myCompany
isEmployeeOf - myCompany
mrCEO
company - myCompany
isEmployeeOf - myCompany
isCEOOf - myCompany