Objective c 核心数据删除规则——对多个关系,空时删除

Objective c 核心数据删除规则——对多个关系,空时删除,objective-c,core-data,Objective C,Core Data,我对核心数据中关系的删除规则是如何工作的有点模糊,至少在文档中描述的简单案例之外 大多数情况下,以及我在这里看到的大多数问题的答案,都使用一个模型,其中一对多关系左侧的对象“拥有”右侧的对象:例如PersonhasPhoneNumbers,如果删除此人,则删除其所有相关号码。在这种情况下,解决方案是明确的:如果您这样设置关系,核心数据将为您处理一切: Person --(cascade)-->> PhoneNumber PhoneNumber --(nullify)--&g

我对核心数据中关系的删除规则是如何工作的有点模糊,至少在文档中描述的简单案例之外

大多数情况下,以及我在这里看到的大多数问题的答案,都使用一个模型,其中一对多关系左侧的对象“拥有”右侧的对象:例如
Person
has
PhoneNumber
s,如果删除此人,则删除其所有相关号码。在这种情况下,解决方案是明确的:如果您这样设置关系,核心数据将为您处理一切:

Person      --(cascade)-->> PhoneNumber
PhoneNumber --(nullify)-->  Person
我感兴趣的是相反的:一种“所有权”颠倒的对多关系。例如,我可以扩展CoreDataBooks示例代码,添加一个
作者
实体,用于在一个地方收集关于唯一作者的所有信息。一本书有一个作者,但是一个作者有很多书。。。但是我们不关心那些我们没有列出书籍的作者。因此,不允许删除其
书籍
关系为非空的
作者
,删除引用特定
作者的最后一本
书籍
应删除该
作者

我可以想象几种手动操作的方法。。。我不确定的是:

  • 核心数据是否有一种方法可以至少自动完成其中的一部分,就像关系删除规则一样
  • 有没有一种“规范的”首选方法来处理这种情况

您可以覆盖
书籍
类中的
preparefordelection
,并检查作者是否还有其他书籍。如果没有,你可以删除作者

- (void)prepareForDeletion {
    Author *author = self.author;
    if (author.books.count == 1) { // only the book itself
        [self.managedObjectContext deleteObject:author];
    }
}
编辑:为了防止删除拥有书籍的作者,您可以覆盖
validateForDelete
或者更好:首先不要对拥有书籍的作者调用deleteObject

检查下面的关系,以完成两个标准

  • 作者--(拒绝)-->>书籍

  • 不允许删除书籍关系为非空的作者

    拒绝:如果关系目标至少有一个对象,则无法删除源对象

    - (void)willSave {
        if (!self.isDeleted) {
            NSPredicate *notDeletedPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary<NSString *,id> *bindings) {
                return ![(NSManagedObject *)evaluatedObject isDeleted];
            }];
            NSSet *filteredBooks = [self.books filteredSetUsingPredicate:notDeletedPredicate];
            if (filteredBooks.count == 0)
                [self.managedObjectContext deleteObject:self];
        }
        [super willSave];
    }
    
  • 书--(级联)-->作者

  • 删除引用特定作者的最后一本书应删除该作者

    您不能删除作者,正如我们的第一条规则所说,如果有任何非空的书籍,则不应删除。如果它们不存在,作者将被删除


    我认为理论上它应该是有效的。让我知道,这是否有效

    与Tim的解决方案类似,您可以覆盖Author
    NSManagedObject
    子类中的
    willSave
    方法。请注意,如果您确实使用了Tim的解决方案,我强烈建议您为尚未删除的书籍筛选书籍集;这样,如果同时删除作者的所有书籍,该作者仍将被删除

    - (void)willSave {
        if (!self.isDeleted) {
            NSPredicate *notDeletedPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary<NSString *,id> *bindings) {
                return ![(NSManagedObject *)evaluatedObject isDeleted];
            }];
            NSSet *filteredBooks = [self.books filteredSetUsingPredicate:notDeletedPredicate];
            if (filteredBooks.count == 0)
                [self.managedObjectContext deleteObject:self];
        }
        [super willSave];
    }
    
    -(void)将保存{
    如果(!self.isDeleted){
    NSPredicate*notDeletedPredicate=[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject,NSDictionary*绑定){
    return![(NSManagedObject*)evaluatedObject已删除];
    }];
    NSSet*filteredBooks=[self.books filteredSetUsingPredicate:notDeletedPredicate];
    if(filteredBooks.count==0)
    [self.managedObjectContext删除对象:self];
    }
    [超级保存];
    }
    
    以下几点对我很有用:

    将您的作者实体的“书籍”关系的删除规则设置为“拒绝”,这意味着只要有一本书链接到您的作者,它就不能被删除

    - (void)willSave {
        if (!self.isDeleted) {
            NSPredicate *notDeletedPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary<NSString *,id> *bindings) {
                return ![(NSManagedObject *)evaluatedObject isDeleted];
            }];
            NSSet *filteredBooks = [self.books filteredSetUsingPredicate:notDeletedPredicate];
            if (filteredBooks.count == 0)
                [self.managedObjectContext deleteObject:self];
        }
        [super willSave];
    }
    
    对book实体进行子类化并重写PrepareForderElection()函数,如下所示:

    public override func prepareForDeletion() {
        super.prepareForDeletion()
        do {
            try author.validateForDelete()
            managedObjectContext?.delete(author)
        } catch {}
    }
    
    除非账簿关系为空,否则Validate for delete将引发错误。
    您可以选择处理错误。

    Author-(Deny)->>Books
    很好,但是
    Book-(Cascade)->Author
    会在删除作者的第一本书时立即删除作者。(要么是这样,要么是我做错了什么。)但是同一个作者被绑定了否认关系的权利,所以理论上它不会被删除,因为他有另一本书。除非有其他事情发生,否则如果一个作者的两本书同时被删除,这似乎是失败的。我正在打印author.books.count在我相应的preparefordelection中的值,这两本书的值都是2。那么作者永远不会被删除。(更改类名以匹配问题,但关系相同。)