我有一个带有Container和Item实体的Core Data模型。 Container可以包含零个或多个项目。一个Item必须属于至少一个Container(但它可以在多个Container中。)
关系看起来像这样:
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
删除Container时会出现问题。该容器中的Item对象已更新,但如果该项目仅存在于一个容器中,则itemContainers属性是一个没有对象的集合。保存对象图失败,因为该空集违反了itemContainers的Item的非可选设置。
当然,使用NSPredicate(例如“itemContainers。@ count == 0”)找到带有空itemContainers的Item对象很容易,但似乎应该有一种方法可以配置模型来自动执行此操作。 / p>
那么有更容易/更好的方法吗?
答案 0 :(得分:4)
我在上面针对类似的问题尝试了Tony Arnold's answer,但是在一次删除多个“容器”时发现了问题(这是在OS X 10.8.2上)。在保存托管对象上下文之前,容器不会从[item itemContainers]
中删除,因此count
仍然高于1,item
永远不会被删除。
我在-[NSManagedObject isDeleted]
上使用NSManagedObject
和类别方法提出了以下解决方案。
档案NSManagedObject+RJSNondeletedObjects.h
#import <CoreData/CoreData.h>
@interface NSManagedObject (RJSNondeletedObjects)
- (NSSet *)RJS_nondeletedObjectsForToManyKeyPath:(NSString *)keyPath;
- (BOOL)RJS_hasOtherNondeletedObjectsForToManyKeyPath:(NSString *)keyPath;
@end
档案NSManagedObject+RJSNondeletedObjects.m
#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
Container
课程
...
#import "NSManagedObject+RJSNondeletedObjects.h"
...
- (void)prepareForDeletion
{
NSSet *childItems = [self items];
for (Item *item in childItems) {
if ([item RJS_hasOtherNondeletedObjectsForToManyKeyPath:@"containers"]) {
continue;
}
[managedObjectContext deleteObject:item];
}
}
答案 1 :(得分:1)
我知道它不像Core Data提供的配置选项一样干净,但是我已经部署了一些项目,其中Container
对象在删除时会循环显示它的子Item
实体,检查如果他们有0 itemContainers
(在'Container.m'里面):
- (void)prepareForDeletion
{
NSSet *childItems = [self items];
for (Item *item in childItems) {
if ([[item itemContainers] count] > 1) {
continue;
}
[managedObjectContext deleteObject:item];
}
}
答案 2 :(得分:0)
在我的应用程序中,我将项目的容器关系设为可选,并通过“智能容器”访问这些无容器项目。
如果你不想这样,我怀疑你只需要处理保存失败,并删除违规对象。
我越来越多地将核心数据的方法转变为防御性数据:假设验证失败,并准备好处理它。在集成iCloud同步时变得更加重要。
答案 3 :(得分:0)
我认为你不能在你的模型中指定这种行为,但是我可以验证你的容器中的itemContainers
的数量
- (void)removeItemObject:(Item *)value
{...
if(![[value itemContainers]count])
[context deleteObject:value];
...
}
答案 4 :(得分:0)
我喜欢这样做:
- (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];
}
}