例如,假设我有一个User
托管对象与friends
关系用户< - >用户多对多。
现在假设有些用户a
,2位用户x
和d
已经处于a
的{{1}}关系中。但那时:
friend
和b
添加到c
。friends
删除了d
(请注意,我不会从上下文中删除对象本身,只需将其从关系中删除)。此时,我想以某种方式告诉friends
关系:
friends
没有任何变化,因为它始终存在。x
和b
位于“插入的集合”中。c
位于“已移除的内容”中。或者,对于关系d
:
friends
,b
和c
有更改,仍然可以告诉d
和b
的更改是“插入”类型而c
的类型为“删除”/“删除”我还没有找到实现这一目标的通用方法。上下文已更新,插入和删除了集,但这是针对上下文的,而不是针对特定关系。
答案 0 :(得分:0)
NSManagedObject可以通过调用- (NSDictionary *)changedValues
为您提供有关其更改的更多信息。但遗憾的是,仅仅跟踪关系变化还不够。下面,我分享了一种我之前使用的技术。您应该在执行save:
之前找到更改。
NSDictionary* relationshipsByName = [[object entity] relationshipsByName];
NSDictionary* changedValues = [object changedValues];
NSManagedObjectContext* contextToCompateChanges = [[NSManagedObjectContext alloc] init];
[contextToCompateChanges setPersistentStoreCoordinator:persistentStoreCoordinator];
for (NSString* propertyName in changedValues) {
NSRelationshipDescription* relationshipDescription = [relationshipsByName objectForKey:propertyName];
if (relationshipDescription == nil]) {
continue;
}
if ([relationshipDescription isToMany]) {
NSSet* changedValue = [changedValues objectForKey:propertyName];
NSManagedObject* oldObject = [contextToCompateChanges objectWithID:[object objectID]];
NSSet* oldValue = [oldObject valueForKey:propertyName];
NSExpression* expr = [NSExpression expressionForKeyPath:@"objectID"];
NSSet* changedIDs = [expr expressionValueWithObject:changedValue context:nil];
NSSet* oldIDs = [expr expressionValueWithObject:oldValue context:nil];
NSMutableSet* insertedSet = [NSMutableSet setWithSet:changedIDs];
[insertedSet minusSet:oldIDs]];
// insertedSet will contain objectsIDs of newly inserted objects
NSMutableSet* deletedSet = [NSMutableSet setWithSet:oldIDs];
[deletedSet minusSet:changedIDs];
// deletedSet will contain objectsIDs of deleted objects
} else {
NSManagedObject* newRelationshipValue = [changedValues objectForKey:propertyName];
if ((NSNull*)newRelationshipValue == [NSNull null]) {
NSManagedObject* oldObject = [contextToCompateChanges objectWithID:[object objectID]];
newRelationshipValue = [oldObject valueForKey:propertyName];
if (newRelationshipValue == nil) {
continue;
}
// newRelationshipValue is object that was deleted from relationsip
} else {
// newRelationshipValue is object that was inserted into relationsip
}
}
}
[contextToCompateChanges release];
希望这对你有所帮助。
答案 1 :(得分:0)
到目前为止,我提出了以下解决方案:
//Assume context, entityName, nameOfRelationship,etc... to be properly defined
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
NSArray *fetchResult = [self.context executeFetchRequest:fetchRequest error:&error];
NSArray *deletedObjects = [fetchResult filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
id relationship = [evaluatedObject changedValues][nameOfRelationship];
return relationship && ![relationship containsObject:self.currentUser];
}]];
NSArray *insertedObjects = [fetchResult filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
id relationship = [evaluatedObject changedValues][nameOfRelationship];
return relationship && [relationship containsObject:self.currentUser];
}]];
此时我有2个插入和删除数组(我知道,我在我的问题中说过设置......但现在这个有效)。
我观察到的一个问题是,为了使其工作,我需要首先从服务器检索数据,将其解析为托管对象,将这些托管对象放在适当的“默认”关系中,然后进行上下文保存。只有在上下文保存后,changedValues
才会反映更改,例如正在删除或插入的对象(如果默认情况下未插入)。
现在真正的问题是上下文中的-save:
保存了所有对象。所以,例如,如果我有两个实体,每个实体都有关系(即两个独立的实体,每个实体都有不同的关系,我的所有示例都适用于两个实体),如果我查看上面的代码,然后发出POST和DELETE请求,然后保存上下文,以便在那时这些对象被“提交”,尝试接下来对另一个实体执行相同操作,并且它的关系将失败,因为上下文保存会清除所有对象的changedValues。