每个核心数据关系都必须具有逆关系吗?


150

假设我有两个Entity类:SocialAppSocialAppType

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

SocialAppType我有三个属性:baseURLnamefavicon

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

我需要逆吗,为什么?

Answers:


117

在实践中,由于没有逆,我没有任何数据丢失-至少我知道。快速的Google建议您使用它们:

逆向关系不仅使事情更整洁,而且实际上是Core Data用来维护数据完整性的。

- 可可开发中心

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

- 核心数据编程指南


5
请参阅MadNik的答案(在我撰写本文时,在页面底部),以更全面地解释文档中所说的逆向关系有助于保持数据完整性的含义。
Mark Amery

135

Apple文档提供了一个很好的示例,该示例提示您可能由于没有逆关系而出现问题。让我们将其映射到这种情况下。

假设您对其建模如下: 在此处输入图片说明

注意:您有一个到一个所谓的“关系 ”,从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为nil。

很奇怪,不是吗?对于非可选属性,我们得到nil吗?

因此,如果您建立了逆关系,您将没有任何麻烦。否则,您必须通过如下编写代码来进行强制验证。

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];

9
这是一个很好的答案。感谢您详细说明了什么-从文档以及从我读过的所有书中可以看出,主要论点是支持对所有事物使用逆,即使逆关系对人类没有意义。这确实应该是公认的答案。Rose Perrone的答案(以及文档中的一些内容)已经详细介绍了您可能选择求逆的原因,因此现在缺少了所有这些问题线索。
Mark Amery

46

我将解释由Dave Mark和Jeff LeMarche 在“ 更多iPhone 3开发”中找到的明确答案。

Apple通常建议您始终创建和指定逆关系,即使您在应用程序中不使用逆关系也是如此。出于这个原因,当您未能提供反函数时,它会警告您。

关系不需要具有逆关系,因为在某些情况下,逆关系可能会损害性能。例如,假设逆关系包含大量对象。删除反函数需要迭代代表反函数的集合,从而降低性能。

但是,除非有特殊原因,否则请对逆模型进行建模。它有助于核心数据确保数据完整性。如果遇到性能问题,以后删除逆关系相对容易。


24

更好的问题是:“有理由求逆吗?” 核心数据实际上是一个对象图管理框架,而不是持久性框架。换句话说,它的工作是管理对象图中对象之间的关系。逆关系使这一过程变得容易得多。因此,Core Data期望逆向关系,并且是针对该用例编写的。没有它们,您将不得不自己管理对象图的一致性。特别是,没有反向关系的一对多关系很可能会被Core Data破坏,除非您非常努力地使事情继续进行。与反向关系的磁盘大小有关的成本与其带来的收益相比,确实是微不足道的。


20

至少在一种情况下,可以为核心数据关系建立良好的关系而无相反:当两个对象之间已经存在另一个核心数据关系时,它将处理维护对象图的过程。

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

但是,您可能还希望跟踪每本书正在阅读的当前页面。可以使用Page上的“ currentPage” 属性来完成此操作,但是随后您需要其他逻辑以确保在任何时候都仅将书中的一页标记为当前页。取而代之的是,从Book到单个页面建立currentPage 关系,将确保始终只标记一个当前页面,此外,仅通过book.currentPage即可通过引用该书轻松访问此页面。

书籍和页面之间核心数据关系的图形表示

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

在概述的示例中,由于没有与“ Nullify”的对等关系,因此currentPage关系的删除规则应设置为“ No Action”或“ Cascade”。(级联意味着您在阅读本书时会将书中的每一页都撕掉,但是如果您特别冷,需要加油,那可能是正确的。)

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


感谢Duncan –这非常接近我的用例。本质上,我需要能够获得一本书的最后一页。我需要将其作为持久值,以便可以在提取谓词中使用它。我已经设置了一个“ bookIAmLastPageOf”逆函数,但是这很荒谬,并且会引起其他问题(我不太了解)。您知道是否有一种方法可以针对单个情况禁用警告吗?
约翰2015年

有没有办法禁用警告?我现在有2个:...应该具有相反的值,并且没有操作删除规则...可能导致与已删除对象的关系。并可以currentPage标记为Optional
SwiftArchitect

将currentPage存储为NSManagedObjectID而不是关系是否有效?
user965972 '16

4

尽管文档似乎不需要逆运算,但我只是解决了一种情况,该场景实际上由于没有逆运算而导致“数据丢失”。我有一个报告对象,该对象在可报告对象上具有多对多关系。如果没有逆关系,则重新启动后对多关系的任何更改都将丢失。在检查了Core Data调试之后,很明显,即使我保存了报表对象,也从未进行过对象图(关系)的更新。我添加了一个逆,即使我不使用它,也可以,它可以工作。因此,它可能不会说这是必需的,但是没有逆关系的关系肯定会产生奇怪的副作用。


0

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

推荐的方法是在两个方向上建模关系,并适当指定逆关系。如果进行更改,Core Data将使用此信息来确保对象图的一致性

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

提供的链接为您提供了为什么应该有一套的想法inverse。没有它,您可能会丢失数据/完整性。同样,您访问对象的nil可能性更高。


0

通常不需要逆关系。但是在Core数据中,很少有需要逆关系的问题/错误。在某些情况下,即使缺少逆关系,即使保存上下文时没有错误,关系/对象也会丢失。检查这个示例,我创建了这个示例来演示在使用Core数据时缺少对象以及如何解决的方法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.