每个核心数据关系都必须有反向吗?

时间:2009-04-18 20:23:50

标签: objective-c core-data

假设我有两个实体类:SocialAppSocialAppType

SocialApp我有一个属性:appURL和一个关系:type

SocialAppType我有三个属性:baseURLnamefavicon

SocialApp关系type的目的地是SocialAppType中的单个记录。

例如,对于多个Flickr帐户,会有一些SocialApp条记录,每条记录都包含指向某个人帐户的链接。 “Flickr”类型将有一个SocialAppType记录,所有SocialApp记录都会指向该记录。

当我使用此架构构建应用程序时,我收到警告,SocialAppTypeSocialApp之间没有反比关系。

 /Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse

我需要反转,为什么?

8 个答案:

答案 0 :(得分:129)

Apple文档有一个很好的例子,表明你可能因为没有反向关系而遇到问题。让我们把它映射到这种情况。

假设您将其建模如下: enter image description here

请注意,您有一个名为“类型”的 to-one 关系,从SocialAppSocialAppType。关系非可选,并且“拒绝”删除规则

现在考虑以下事项:

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];
BOOL saved = [managedObjectContext save:&error];

我们期望失败此上下文保存,因为我们已将删除规则设置为拒绝,而关系不是可选的。

但是保存成功了。

原因是我们没有设置反向关系。因此,当删除appType时,socialApp实例不会被标记为已更改。因此,在保存之前没有对socialApp进行验证(它假定不需要验证,因为没有发生任何更改)。但实际上发生了变化。但它没有得到反映。

如果我们通过

回忆appType
SocialAppType *appType = [socialApp socialAppType];

appType为零。

很奇怪,不是吗?我们得到一个非可选属性为零

如果你设置了反向关系,那么你没有遇到麻烦。 否则,您必须通过编写代码进行强制验证,如下所示。

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];

[socialApp setValue:nil forKey:@"socialAppType"]
BOOL saved = [managedObjectContext save:&error];

答案 1 :(得分:111)

在实践中,由于没有反向,我没有任何数据丢失 - 至少我知道。谷歌快速建议你应该使用它们:

  

反向关系不仅仅是   让事情更整洁,实际上   Core Data用于维护数据   完整性。

- Cocoa Dev Central

  

您通常应该建模   两个方向的关系,和   指定反向关系   适当。核心数据使用此功能   信息,以确保一致性   对象图的变化是否为   制作(参见“操纵关系”   和对象图完整性“)。为一个   讨论了一些原因   你可能想要不打模   两个方向的关系,和   可能出现的一些问题   如果不这样做,请参阅“单向   关系。”

- Core Data Programming Guide

答案 2 :(得分:46)

答案 3 :(得分:24)

更好的问题是,“有没有理由有逆转”?核心数据实际上是一个对象图管理框架,而不是一个持久性框架。换句话说,它的工作是管理对象图中对象之间的关系。反向关系使这个更多更容易。因此,Core Data需要反向关系,并针对该用例编写。没有它们,您将不得不自己管理对象图的一致性。特别是,没有反向关系的多对多关系很可能被Core Data破坏,除非你非常难以保持工作。与其获得的收益相比,反向关系的磁盘大小成本确实微不足道。

答案 4 :(得分:20)

至少有一种情况可以在没有逆的情况下为核心数据关系提供良好的案例:当两个对象之间已存在另一个核心数据关系时,它将处理维护对象图。

例如,一本书包含许多页面,而一个页面在一本书中。这是一种双向的多对一关系。删除页面只会使关系无效,而删除书籍也会删除页面。

但是,您可能还希望跟踪每本书正在阅读的当前页面。这可以通过 Page 上的“currentPage”属性来完成,但是您需要其他逻辑来确保书中只有一个页面被标记为当前页面时间。相反,将Book中的currentPage 关系设置为单个页面将确保始终只标记一个当前页面,此外,只需通过参考书籍即可轻松访问此页面.currentPage。

Graphical presentation of core data relationship between books and pages

在这种情况下,互惠关系会是什么?一些很大程度上荒谬的东西。 “myBook”或类似内容可以在另一个方向上添加回来,但它只包含页面“book”关系中已包含的信息,因此会产生自己的风险。也许在将来,您使用这些关系之一的方式会发生变化,从而导致核心数据配置发生变化。如果在某些已经在代码中使用了page.book的地方使用了page.myBook,则可能会出现问题。另一种主动避免这种情况的方法也是不将myBook暴露在用于访问页面的NSManagedObject子类中。然而,可以认为,首先不对逆进行建模更为简单。

在概述的示例中,currentPage关系的删除规则应设置为“No Action”或“Cascade”,因为与“Nullify”没有对等关系。 (Cascade暗示你在阅读时会翻阅书中的每一页,但如果你特别冷,需要加油,那可能就是这样。)

当可以证明对象图完整性没有风险时,如本例所示,并且代码复杂性和可维护性得到改善,可以认为没有逆的关系可能是正确的决策。

答案 5 :(得分:4)

虽然文档似乎不需要反向,但我刚刚解决了一个实际上由于没有反转导致“数据丢失”的情况。我有一个报表对象,它在可报告对象上具有多对多关系。如果没有反比关系,重新启动时对多对多关系的任何更改都会丢失。在检查Core Data调试之后,很明显即使我保存了报表对象,也从未对对象图(关系)进行更新。我添加了一个逆,即使我不使用它,瞧,它的工作原理。所以它可能不会说它是必需的,但没有反转的关系肯定会有奇怪的副作用。

答案 6 :(得分:0)

逆也用于Object Integrity(出于其他原因,请参见其他答案):

  

推荐的方法是在两个方向上建模关系   并适当指定逆关系。核心数据用途   此信息可确保对象图的一致性,如果   做出改变

发件人:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1

提供的链接为您提供了一个为什么要设置inverse的想法。没有它,您可能会丢失数据/完整性。另外,您更有可能访问nil对象。

答案 7 :(得分:0)

通常不需要逆关系。但是在Core数据中,很少有需要逆关系的问题/错误。在某些情况下,即使缺少逆关系,即使保存上下文时没有错误,关系/对象也会丢失。选中此example,这是我创建的,目的是演示在处理核心数据时缺少的对象以及解决方法