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

假设我有两个实体类: 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

我需要反转,为什么?

回答(6)

2 years ago

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

反向关系不仅使事情更加整洁,它实际上被Core Data用于维护数据完整性 .

您通常应该在两个方向上建模关系,并适当地指定反向关系 . 如果进行了更改,Core Data会使用此信息来确保对象图的一致性(请参阅“操作关系和对象图完整性”) . 有关您可能不希望在两个方向上 Build 关系模型的一些原因的讨论,以及如果不这样做可能会出现的一些问题,请参阅“单向关系” .

2 years ago

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

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

请注意,您有一个名为“ type ”的 to-one 关系,从 SocialAppSocialAppType . 这段关系是 non-optional 并且有 "deny" delete rule .

现在考虑以下内容:

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

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

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

But here the save succeeds.

原因是我们没有设置 inverse relationship . 因此,删除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];

2 years ago

我将解释我在Dave Mark和Jeff LeMarche撰写的更多iPhone 3开发中找到的明确答案 .

Apple generally recommends that you always create and specify the inverse, even if you don't use the inverse relationship in your app. 因此,当您未能提供反向时,它会发出警告 .

关系不需要具有逆,因为在一些场景中,逆关系可能会损害性能 . 例如,假设反向关系包含极大数量的对象 . 删除逆需要迭代表示反向弱化性能的集合 .

unless you have a specific reason not to, model the inverse . 它有助于核心数据确保数据完整性 . 如果遇到性能问题,以后删除反向关系相对容易 .

2 years ago

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

2 years ago

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

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

但是,您可能还希望跟踪每本书正在阅读的当前页面 . 这可以通过Page上的"currentPage"属性来完成,但是您需要其他逻辑来确保书中只有一个页面随时被标记为当前页面 . 相反,从Book到单个页面 Build currentPage关系将确保这一点将始终只标记一个当前页面,此外,只需使用book.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暗示你在阅读时会翻阅书中的每一页,但如果你特别冷,需要燃料,这可能是真的 . )

当可以证明对象图完整性没有风险时,如在这个例子中,并且代码复杂性和可维护性得到改善,可以认为没有逆的关系可能是正确的决定 .

2 years ago

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