在删除一对一关系的核心数据期间发现 NSManagedObject 的问题

Posted

技术标签:

【中文标题】在删除一对一关系的核心数据期间发现 NSManagedObject 的问题【英文标题】:Issues finding NSManagedObject during Core Data deletion for to-one relationship 【发布时间】:2013-01-02 20:39:17 【问题描述】:

更新:下面的 Martin R 提供了一个非常清晰(简洁!)的答案,几乎回答了我的问题。我想我应该改写:

在调用prepareForDeletion 时,如果这些对象与被删除的对象一对一地连接,你能想到为什么无法获取连接到另一个 NSManagedObject 的 NSManagedObject 的任何原因吗?

我需要能够调用prepareForDeletion,以便在决定是否应该删除对象的子对象之前运行一些实体检查。


在Core Data中删除对象的子对象是一对一关系时,有什么技巧吗?

我有一个相当复杂的核心数据模型,其中删除单个 NSManagedObject 还应该通过prepareForDeletion 删除其子 NSManagedObjects。在删除之前立即运行一系列调试 NSLog 语句表明所有关系都已正确设置。然而,当实际尝试删除对象时,似乎许多(尽管不是全部)这些关系已经丢失,因为尝试通过 NSFetchRequest 获取这些对象中的一些(但同样,不是全部)返回空数组。

我似乎无法弄清楚我如何获取找到的对象与未找到的对象之间的任何区别,除了找到的对象是多对数的反比关系,而无法找到的对象是一对一的关系:-/

要删除“主”对象,我只需调用[managedObjectContext deleteObject:mainObject];,并在主对象的私有API 中覆盖prepareForDeletion,如下所示:

- (void)prepareForDeletion

//    [super prepareForDeletion]; // commented but uncommenting doesn't change results
    [MyDataManager deleteChildOneForMainObject:self];
    [MyDataManager deleteChildrenTwoForMainObject:self];
    [MyDataManager deleteChildrenThreeForMainObject:self];

MyDataManager 是一个只包含类方法的自定义 NSObject。 MyDataManager 然后通过类似于以下内容在托管对象上下文中搜索相应的 NSManagedObjects:

- (BOOL)deleteChildOneForMainObject:(MainObject *)mainObject

    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ChildOne" inManagedObjectContext:managedObjectContext];
    [fetch setEntity:entity];
    [fetch setPredicate:[NSPredicate predicateWithFormat:@"(mainObject == %@)", mainObject]];
    NSError *error;
    NSArray *childOnesToDelete = [managedObjectContext executeFetchRequest:fetch error:&error];
    if (childOnesToDelete.count > 1)
    
        NSLog(@"[WARNING] More than one ChildOne for mainObject found; deleting all");
    
    NSLog(@"[TEST] Deleting %i ChildOnes", childOnesToDelete.count);
    for (ChildOne *childOne in childOnesToDelete)
    
        [managedObjectContext deleteObject:childOne];
    
    if ([managedObjectContext save:&error]) return YES;
    else NSLog(@"[WARNING] Save error for function [deleteChildOneForMainObject:]");
    return NO;

同样,每个“MainObject”类型的 NSManagedObject 与“ChildOne”具有一对一关系,与“ChildTwo”和“ChildThree”具有一对多关系。 “Child One”、“ChildTwo”和“ChildThree”都与“MainObject”具有一对一的关系。

【问题讨论】:

一个更简单的解决方案可能是将关系的“删除规则”设置为从 MainObjectChildX 到“Cascade”。那么删除 MainObject 实体的一个对象会自动删除 ChildX 实体的所有相关对象。 正如@MartinR 建议的那样,您应该使用删除规则。你使用什么类型的规则?看看这里developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/… ChildXMainObject 设置无效。这意味着:如果一个孩子被删除,对父母不做任何事情。 “级联”是否深入 1 级?如果其他对象也在层次结构中,我将如何防止它们被删除?例如,ChildTwo 也一对一地绑定到对象 HouseOne,但我不希望在通过 MainObject 删除 ChildTwo 时删除 HouseOne。 @KenHaggerty:这取决于从 ChildTwo 到 HouseOne 的删除规则,因此您可以单独控制。 【参考方案1】:

如果您正确设置关系的“删除规则”,Core Data 可以自动处理删除“依赖”对象。在这种情况下,您可以设置

删除从MainObjectChildX到“Cascade”的关系规则, 删除从 ChildXMainObject 到“Nullify”的反向关系规则。

意思是

如果一个 MainObject 被删除,相关的 ChildX 对象也会被删除。 如果 ChildX 对象被删除,则相关 MainObject 中的关系值将设置为 NULL。

【讨论】:

好吧。我没有意识到删除规则是单向的。【参考方案2】:

所以我终于让 IRC 为我工作了! #iphonedev 频道上的一位乐于助人的人提供了以下见解:

•(就像 Martin R 所说)我应该忍受用于构建我的核心数据模型的可视化界面,并使用提供的“删除规则”下拉菜单来创建我的删除逻辑。 (在“Utilities”右侧窗格中,第三个选项卡看起来像一块奶酪。)“Cascade”和“Nullify”是最有用的值。

• “删除规则”是单向的,并且对每个关系都是唯一的,因此您有相当程度的控制权。

• 无需获取与提供的 NSManagedObject 具有一对一关系的 NSManagedObject,只需使用该属性即可。使用 fetch 作为“保护”机制是愚蠢和不必要的,因为根据定义,这种关系是一对一的。所以如果我有YingYang 对象,我应该只执行[managedObjectContext deleteObject:ying.yang][managedObjectContext deleteObject:yang.ying]

根据 Martin R 的回答,最终 prepareForDeletion 仅与级联删除有关。

【讨论】:

有没有办法“接受”两个答案? Martin R 的回答是解决方案的 66%。 不,很遗憾不是 :-) 根据常见问题解答,应该接受“最有帮助”的答案。如果你接受你自己的答案是完全可以的(我不会有问题的)。

以上是关于在删除一对一关系的核心数据期间发现 NSManagedObject 的问题的主要内容,如果未能解决你的问题,请参考以下文章

iphone核心数据:无法删除具有一对多关系的数据

核心数据:删除最后一个具有一对多关系的实体

iOS:删除核心数据中具有一对多关系的实体

了解一对多的核心数据删除规则

不允许更改核心数据关系,但最终允许删除子项

使用核心数据,当一对多关系低于最小计数时,是一种自动删除实体的方法吗?