iOS SDK上的错误或我对继承实体关系的误解?

时间:2011-08-26 16:01:24

标签: inheritance core-data

我几天前遇到这个问题(link )。在简单的例子中将简短地说明这一点。我有公司实体,其中包含许多实体员工和一个实体CEO(继承自员工)。

完成我的数据模型后,我向该公司增加了5名员工,我将首席执行官分配到该公司。在测试时,我打电话给company.employees,预计会有5名员工,但结果与我的预期不一样,我也将CEO作为我的员工之一。

从这个事件中感到震惊我开始搜索关于apple doc的解释,我看到两篇相关的文章Fetching and Entity Inheritance

  

如果您定义实体继承层次结构(请参阅“实体   继承“),指定一个超级实体作为一个实体   获取请求,请求返回所有匹配的实例   超实体和子实体。

Relationship Fundamentals

  

关系指定实体或父实体   目的地的物体。这可以与实体相同   来源(反身关系)。关系不一定是   同质。如果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属性中。

1 个答案:

答案 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