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");
输出:
可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 可以删除员工 警告:无法删除部门
令我惊讶的是,canDelete
是 NO
。当员工对象不无效时,为什么部门对象无效删除?返回的错误包含以下内容(略)
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<<--->>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?