假设我有两个实体类:SocialApp
和SocialAppType
在SocialApp
我有一个属性:appURL
和一个关系:type
.
在SocialAppType
我有三个属性:baseURL
,name
和favicon
.
SocialApp
关系的目的地type
是单个记录SocialAppType
.
例如,对于多个Flickr帐户,会有许多SocialApp
记录,每条记录都包含指向某个人帐户的链接.会有一个SocialAppType
针对"Flickr的"类型的记录,所有SocialApp
记录将指向.
当我使用这个模式构建一个应用程序时,我得到一个警告,即SocialAppType
和之间没有反比关系SocialApp
.
/Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse
我需要反转,为什么?
Apple文档有一个很好的例子,表明你可能因为没有反向关系而遇到问题.让我们把它映射到这种情况.
假设您将其建模如下:
注意:您有一个到一个所谓的"关系型 ",从SocialApp
到SocialAppType
.该关系是非可选的,并且具有"拒绝"删除规则.
现在考虑以下内容:
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];
在实践中,由于没有反向,我没有任何数据丢失 - 至少我知道.谷歌快速建议你应该使用它们:
反向关系不仅使事情更加整洁,它实际上被Core Data用于维护数据完整性.
- Cocoa Dev Central
您通常应该在两个方向上建模关系,并适当地指定反向关系.如果进行了更改,Core Data会使用此信息来确保对象图的一致性(请参阅"操作关系和对象图完整性").有关您可能不想在两个方向上建模关系的一些原因的讨论,以及可能出现的一些问题,请参阅"单向关系".
- 核心数据编程指南
我将解释我在Dave Mark和Jeff LeMarche的更多iPhone 3开发中找到的明确答案.
Apple通常建议您始终创建并指定反向,即使您不在应用程序中使用反向关系.因此,当您未能提供反向时,它会发出警告.
关系不需要具有逆,因为在一些场景中,逆关系可能会损害性能.例如,假设反向关系包含极大数量的对象.去除逆需要迭代表示反向弱化性能的集合.
但除非你有特殊的理由不这样做,否则建模.它有助于核心数据确保数据完整性.如果遇到性能问题,以后删除反向关系相对容易.
更好的问题是,"有没有理由不反过来"?核心数据实际上是一个对象图管理框架,而不是一个持久性框架.换句话说,它的工作是管理对象图中对象之间的关系.反向关系使这更容易.因此,Core Data需要反向关系,并针对该用例编写.没有它们,您将不得不自己管理对象图的一致性.特别是,没有反向关系的多对多关系很可能被Core Data破坏,除非你非常努力地保持工作.与获得的收益相比,反向关系的磁盘大小成本确实微不足道.
至少有一种情况可以在没有逆的情况下为核心数据关系建立良好的情况:当两个对象之间存在另一个核心数据关系时,它将处理维护对象图.
例如,一本书包含许多页面,而一个页面在一本书中.这是一种双向的多对一关系.删除页面只会使关系无效,而删除书籍也会删除页面.
但是,您可能还希望跟踪每本书的当前页面.这可以通过Page上的"currentPage" 属性来完成,但是您需要其他逻辑来确保书中只有一个页面随时被标记为当前页面.相反,从Book到单个页面建立currentPage 关系将确保始终只标记一个当前页面,而且只需使用book.currentPage参考书籍就可以轻松访问此页面.
在这种情况下,互惠关系会是什么?一些很大程度上荒谬的东西."myBook"或类似内容可以在另一个方向上添加回来,但它只包含页面"book"关系中已包含的信息,因此会产生自己的风险.也许在将来,您使用这些关系之一的方式会发生变化,从而导致核心数据配置发生变化.如果在某些已经在代码中使用了page.book的地方使用了page.myBook,则可能会出现问题.另一种主动避免这种情况的方法也是不将myBook暴露在用于访问页面的NSManagedObject子类中.但是,可以认为,首先不对逆进行建模更为简单.
在概述的示例中,currentPage关系的删除规则应设置为"No Action"或"Cascade",因为与"Nullify"没有相互关系.(Cascade暗示你在阅读时会翻阅书中的每一页,但如果你特别冷,需要加油,那可能就是这样.)
当可以证明对象图完整性没有风险时,如在这个例子中,并且代码复杂性和可维护性得到改善,可以认为没有逆的关系可能是正确的决定.