Core data 多对多关系的核心数据删除规则
我有一个包含容器和项目实体的核心数据模型。容器中可以有零个或多个项目。项目必须至少属于一个容器(但可以位于多个容器中) 这些关系如下所示:Core data 多对多关系的核心数据删除规则,core-data,nspredicate,object-model,Core Data,Nspredicate,Object Model,我有一个包含容器和项目实体的核心数据模型。容器中可以有零个或多个项目。项目必须至少属于一个容器(但可以位于多个容器中) 这些关系如下所示: Container: Relationship: items, Destination: Item, Inverse: itemContainers Optional, To-Many Relationship Delete Rule: Nullify Item: Relationship: itemContainers, Destinat
Container:
Relationship: items, Destination: Item, Inverse: itemContainers
Optional, To-Many Relationship
Delete Rule: Nullify
Item:
Relationship: itemContainers, Destination: Container, Inverse: items
Not-Optional, To-Many Relationship
Delete Rule: Cascade
删除容器时会出现问题。该容器中的项对象将被更新,但如果该项仅存在于一个容器中,则itemContainers属性是一个不包含任何对象的集。保存对象图失败,因为该空集违反了itemContainers的项非可选设置
当然,使用NSPredicate(如“itemContainers@count==0”)很容易找到带有空itemContainers的Item对象,但似乎应该有一种方法来配置模型以自动执行此操作
那么有没有更简单/更好的方法呢?我知道它没有核心数据提供的配置选项那么干净,但是我部署了一些项目,其中
容器对象在删除它的子项实体时循环,检查它们是否有0项容器(在“Container.m”内):
在我的应用程序中,我将项目的容器关系设置为可选,并通过“智能容器”访问那些无容器项目
如果您不想这样做,我怀疑您将不得不处理保存失败,并删除违反规则的对象
我越来越多地将我处理核心数据的方法改为防御性的方法:假设验证将失败,并准备好处理它。集成iCloud sync时变得更为重要。我认为您不能在模型中指定此行为,但我可以验证容器的
- (void)removeItemObject:(Item *)value
{...
if(![[value itemContainers]count])
[context deleteObject:value];
...
}
我在上面尝试了一个类似的问题,但在一次删除几个“容器”时发现了问题(这在OS X 10.8.2上)。在保存托管对象上下文之前,容器不会从[item itemContainers]
中删除,因此count
保持在1以上,item
永远不会被删除
我使用-[NSManagedObject isDeleted]
和NSManagedObject
上的分类方法提出了以下解决方案
文件NSManagedObject+rjsnondeletedbjects.h
#import <CoreData/CoreData.h>
@interface NSManagedObject (RJSNondeletedObjects)
- (NSSet *)RJS_nondeletedObjectsForToManyKeyPath:(NSString *)keyPath;
- (BOOL)RJS_hasOtherNondeletedObjectsForToManyKeyPath:(NSString *)keyPath;
@end
#import "NSManagedObject+RJSNondeletedObjects.h"
@implementation NSManagedObject (RJSNondeletedObjects)
- (NSSet *)RJS_nondeletedObjectsForToManyKeyPath:(NSString *)keyPath
{
NSSet * result = nil;
id allObjectsForKeyPath = [self valueForKeyPath:keyPath];
if ( ![allObjectsForKeyPath isKindOfClass:[NSSet class]] ) return result;
result = [(NSSet *)allObjectsForKeyPath objectsPassingTest:^BOOL(id obj, BOOL *stop)
{
BOOL testResult = ![obj isDeleted];
return testResult;
}];
return result;
}
- (BOOL)RJS_hasOtherNondeletedObjectsForToManyKeyPath:(NSString *)keyPath
{
BOOL result = NO;
// self will be in the set of nondeleted objects, assuming it's not deleted. So we need to adjust the test threshold accordingly.
NSUInteger threshold = [self isDeleted] ? 0 : 1;
NSSet * nondeletedObjects = [self RJS_nondeletedObjectsForToManyKeyPath:keyPath];
result = ( [nondeletedObjects count] > threshold );
return result;
}
@end
容器
类
...
#import "NSManagedObject+RJSNondeletedObjects.h"
...
- (void)prepareForDeletion
{
NSSet *childItems = [self items];
for (Item *item in childItems) {
if ([item RJS_hasOtherNondeletedObjectsForToManyKeyPath:@"containers"]) {
continue;
}
[managedObjectContext deleteObject:item];
}
}
我喜欢这样做:
- (void)didChangeValueForKey:(NSString *)inKey withSetMutation:(NSKeyValueSetMutationKind)inMutationKind usingObjects:(NSSet *)inObjects
{
[super didChangeValueForKey:inKey withSetMutation:inMutationKind usingObjects:inObjects];
if ([inKey isEqualToString:@"YOURRELATIONSHIP"] && self.YOURRELATIONSHIP.count == 0) {
[self.managedObjectContext deleteObject:self];
}
}
- (void)didChangeValueForKey:(NSString *)inKey withSetMutation:(NSKeyValueSetMutationKind)inMutationKind usingObjects:(NSSet *)inObjects
{
[super didChangeValueForKey:inKey withSetMutation:inMutationKind usingObjects:inObjects];
if ([inKey isEqualToString:@"YOURRELATIONSHIP"] && self.YOURRELATIONSHIP.count == 0) {
[self.managedObjectContext deleteObject:self];
}
}