CoreData - 如何使用 validateForDelete:确定是不是应删除托管对象

Posted

技术标签:

【中文标题】CoreData - 如何使用 validateForDelete:确定是不是应删除托管对象【英文标题】:CoreData - How to use validateForDelete: to determine if a managed object should be deletedCoreData - 如何使用 validateForDelete:确定是否应删除托管对象 【发布时间】:2013-12-21 19:37:59 【问题描述】:

目标:我想检查一个托管对象以确保它可以删除

期望: -[NSManagedObject validateForDelete:] 应该根据托管对象模型中设置的删除规则返回 BOOL


NSManagedObject 类参考

validateForDelete:

确定接收器是否可以在其当前状态下被删除。

- (BOOL)validateForDelete:(NSError **)error

参数

错误

如果接收器在其当前状态下无法删除,则返回时包含描述问题的 NSError 实例。

返回值

YES如果接收者可以在其当前状态下被删除,否则NO

讨论

如果对象的关系具有“拒绝”删除规则并且该关系具有目标对象,则无法删除该对象。

NSManagedObject 的实现向接收者的实体描述发送一条消息,该消息根据值的存在与否执行基本检查。

读到这里,我认为我应该能够做这样的事情:

BOOL canDelete = [myManagedObject validateForDelete:&error];

if (canDelete) 
    [managedObjectContext deleteObject:myManagedObject];

else 
    [self requestUserFeedback];

然而,这个方法几乎总是返回NO


示例代码

托管对象模型

Department
 - Attribute: name  
     - Value: String
 - Relationship: employees
     - To Many
     - Destination: Employee
     - Delete Rule: Nullify
     - Inverse: department

Employee
 - Attribute: name
     - Value: String
 - Relationship: department
     - To One
     - Destination: Department
     - Delete Rule: Nullify
     - Inverse: employees

示例代码:

NSManagedObject *department = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:self.managedObjectContext];

for (int i = 0; i < 10; i++) 
    NSManagedObject *employee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:self.managedObjectContext];
    [employee setValue:department forKey:@"department"];
    if ([employee validateForDelete:NULL]) 
        NSLog(@"Can delete employee");
    
    else 
        NSLog(@"WARNING: Cannot delete employee");
    


NSError *error;
BOOL canDelete = [department validateForDelete:&error];
if (canDelete) 
    NSLog(@"Can delete department");

else 
    NSLog(@"WARNING: Cannot delete department");

输出:

可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 警告:无法删除部门

令我惊讶的是,canDeleteNO。当员工对象不无效时,为什么部门对象无效删除?返回的错误包含以下内容(略)

Error Domain=NSCocoaErrorDomain
Code=1600
UserInfo= <>
    NSValidationErrorObject=< department object >
    NSValidationErrorKey=employees
    NSValidationErrorValue=Relationship 'employees' on managed object

所以,validateForDelete: 没有返回我对多对关系的期望值,但确实返回了对一关系的预期值。但是,回到文档一秒钟:

如果一个对象的关系具有[原文如此]“拒绝”删除规则并且该关系具有目标对象,则无法删除该对象。

NSManagedObject 的实现向接收者的实体描述发送一条消息,该消息根据值的存在与否执行基本检查。

这表明 validateForDelete: 的默认实现是如何工作的,并努力引起对“拒绝”删除规则的注意。没有提及无效或级联删除规则或一对一或多对多关系之间的差异。


进一步研究

Google 搜索出现this hit on the Apple Mailing List archives from 2009,它基本上说:-[NSManagedObject validateForDelete:] 是子类的挂钩,您需要在单独的方法中实现自己的逻辑来确定对象是否可以删除。

什么?这是真的?这不是这种方法的文档会让人相信的:

确定接收器是否可以在其当前状态下被删除。


我们应该如何检查托管对象是否处于可以删除的状态?

我在GitHub 上建立了一个小型示例项目,它通过生产代码和单元测试说明了我的发现。

【问题讨论】:

如果您需要在删除对象之前使用自定义验证,该方法很有用。因此,您可以覆盖它以在那里添加您的自定义删除逻辑。如果你这样做,你应该调用超类实现。 关于您的模型,我无法理解两件事。首先,如果你有一个 to-many rel,一个员工怎么可能属于更多的部门呢?其次,您应该将员工 rel 建模为级联,而部门将被取消。看看***.com/questions/15232092/…。 Department&lt;&lt;---&gt;&gt;Employee 我选择员工/部门,因为这是最常用的示例。你是对的,作为一个问题域,它没有逻辑意义——为了清楚起见,这只是一个例子。 :-) 只看下面的答案。 ***.com/questions/3031790/… 和 ***.com/questions/15545179/… 这非常不令人满意,尤其是文档指出:“Core Data 仅在保存操作期间或根据请求应用验证约束(您可以在任何有意义的时候直接调用验证方法)为您的应用程序流程)。“developer.apple.com/library/mac/documentation/Cocoa/Reference/… 【参考方案1】:

我阅读文档的方式是您应该对其进行子类化,但您的子类也应该首先调用super,这样如果框架本身有验证,您也会捕获它。

根据我的经验,-validateForDelete: 只会在拒绝规则上返回 NO

我的建议是将关系规则设置为“无操作”,然后在您的子类中实现逻辑。

在您的子类中,您可以检查与部门/教室的关系,如果计数为零,则返回YES。非常简单的删除验证规则,无法在模型中实现。

【讨论】:

以上是关于CoreData - 如何使用 validateForDelete:确定是不是应删除托管对象的主要内容,如果未能解决你的问题,请参考以下文章

CoreData - 如何使用 NSPrivateQueueConcurrencyType 使用临时上下文执行 NSFetchRequest?

如何使用 Swift 删除 coredata 中的特定记录?

如何使用 Swift3 访问 CoreData 中的数据索引

如何开始使用 SQLite、iCloud 和 CoreData?

如何在 SwiftUI 中使用 CoreData 更改数据值?

如何一起使用Codable和Coredata?