执行删除规则时未调用自定义对多关系访问器方法

Posted

技术标签:

【中文标题】执行删除规则时未调用自定义对多关系访问器方法【英文标题】:Custom To-Many Relationship Accessor Methods not called when delete rule is executed 【发布时间】:2014-11-14 01:17:14 【问题描述】:

我有一个问题我不明白..

我有一个包含集合和 CD 的简单核心数据模型。每张 CD 都可以添加到多个集合中,因此我添加了一个中间对象来实现这一点。 (编辑:这是我的 DataModel 的简化。在集合中嵌套集合需要中间对象)

因此,当将 CD 添加到收藏夹时,它看起来像这样: (IM是中间对象)

|==========|         |==========|         |==========|
|          |         |          |         |          |
|Collection|=========|   IM     |=========|    CD    |
|          |         |          |         |          |
|==========|         |==========|         |==========|

我已经设置了删除规则,这样如果用户删除了 CD,则 IM 对象被级联删除,并且在删除 IM 对象时,集合属性为零。这就像我想要的那样。数据库中没有剩菜。

但奇怪的是,如果我重写用于从集合中删除 IM 的自定义一对多关系访问器方法(我假设会调用它),什么也不会发生。

我正在使用 Apple 在其核心数据编程指南中提供的内容。 the link

对于单个对象:

- (void)removeEmployeesObject:(Employee *)value
  
      NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
      [self willChangeValueForKey:@"employees"
            withSetMutation:NSKeyValueMinusSetMutation
            usingObjects:changedObjects];
      [[self primitiveEmployees] removeObject:value];
      [self didChangeValueForKey:@"employees"
            withSetMutation:NSKeyValueMinusSetMutation
            usingObjects:changedObjects];

用于移除多个对象:

- (void)removeEmployees:(NSSet *)value
  
      [self willChangeValueForKey:@"employees"
            withSetMutation:NSKeyValueMinusSetMutation
            usingObjects:value];
      [[self primitiveEmployees] minusSet:value];
      [self didChangeValueForKey:@"employees"
            withSetMutation:NSKeyValueMinusSetMutation
            usingObjects:value];

(取自 pdf,他们在这里使用 Employee 作为一对多关系)

但是这些方法在删除规则执行的时候并没有被调用!

所以我的问题:IM 对象被级联删除,但这些方法都没有使用。如何检测 Core Data 所做的删除操作?

还有其他方法吗?

我想知道这一点,因为我想在所有已更改的 Collection 上设置一个“dirtyFlag”,这样我就可以为这些对象更新一些内容。 (其他属性,这里不解释)

(对象上的 KVO 是没用的。我不能去观察完整的数据库,可以吗?还是应该为这个属性 Collection 对象 KVO 本身?)

希望有人可以帮助我!

【问题讨论】:

【参考方案1】:

或者,您可以在您的 IM managedObject 子类中实现 -prepareForDeletion。核心数据在 managedObject 被从 managedObjectContext 中删除之前自动调用 -prepareForDeletion

当调用-prepareForDeletion 时,所有关系仍然可用,您可以将自定义-willDeleteIntermediateObject: 消息发送到所有包含集合,将self 作为参数传递。

然后你可以实现-[Collection willDeleteIntermediateObject:] 来检查它是否是它包含的最后一个 IM 对象,如果是,让它从它的 managedObjectContext 中删除自己。

// IM.m
- (void)prepareForDeletion 
    [super prepareForDeletion];

    for (Collection *collection in self.collections) 
        [collection willDeleteIntermediateObject:self];
    


// Collection.m
- (void)willDeleteIntermediateObject:(IM *)im 
    if (self.intermediateObjects.count == 1 && [self.intermediateObjects.containsObject:im]) 
        [self.managedObjectContext deleteObject:self];
    

【讨论】:

请注意,self.intermediateObjects.count 在删除此实例之前给出了集合中 IM 对象的数量。因此,如果您需要在删除一个 IM 对象后删除一个包含一个 IM 对象的集合,请与 2 进行比较 哇!完全忽略了这种方法。 Apple 的核心数据编程指南 (!!!) 中没有提到这种方法。这是我需要的,所以将其标记为答案。谢谢! 是的,我知道... RTFM ;)【参考方案2】:

您是否正在使用获取的属性修改数据?在这种情况下不会调用可变集合访问器方法。

如果您想在每次删除时都设置脏标志,那么简单地注册NSManagedObjectContextObjectsDidChangeNotification 通知可能是一种更好的模式。使用NSDeletedObjectsKey 键将删除的对象从userInfo 字典中取出。那时你可以在他们的收藏上设置脏标志。

【讨论】:

谢谢亚伦。我会调查这是否可以成为我的解决方案。假设用户将 2 张 CD 添加到收藏中。并从该集合中删除 1 张 CD。我的逻辑规定可以删除带有 1 张 CD 的集合。所以我扫描数据库中的这些案例,并删除这些项目。这将再次触发通知。所以我担心我最终会陷入这个循环,我想提高效率。所以放入一个 while 循环:当有“脏”集合时,扫描这些集合并删除只有 1 张 CD 的集合。并再次启动 while 循环。我希望我能清楚地解释自己。我会尝试你的建议。谢谢!!! ps 我不确定“使用获取的属性修改数据”是什么意思 我会避免花时间优化,除非你确定你确实有一个可衡量的低效率。 See this link 关于获取的属性。 感谢亚伦的链接。不,我没有使用获取的属性。

以上是关于执行删除规则时未调用自定义对多关系访问器方法的主要内容,如果未能解决你的问题,请参考以下文章

CoreData:第一次加载 NSManagedObject 时未访问自定义属性访问器

Core Data 自定义访问器甚至没有被调用

Android 存储访问框架 - 自定义文件类型的启动选择器

如何在 Spring 身份验证管理器之前执行自定义处理程序

如何将方法调用传递到自检器中的 Action、Func 或 Delegate 以获取自定义规则?

从 Xamarin 表单元素共享代码访问自定义渲染器实例