Ios 是否有一种通用方法来获取从核心数据关系中插入或删除的NSManagedObject集?
例如,假设我有一个Ios 是否有一种通用方法来获取从核心数据关系中插入或删除的NSManagedObject集?,ios,core-data,nsmanagedobject,Ios,Core Data,Nsmanagedobject,例如,假设我有一个User托管对象,该对象与friends关系为UserUser多对多。 现在让我们假设对于某个用户a,2个用户x和d已经处于a的朋友关系中。但是: 我将用户b和c添加到friends 我将d从friends中删除(请注意,我没有从上下文中删除对象本身,只是将其从关系中删除) 在这一点上,我想以某种方式告诉大家,对于朋友关系: x没有任何更改,因为它始终存在 b和c在“插入集”中 d位于“已删除集”中 或者,对于关系朋友: b、c和d有变化,并且仍然能够辨别b和c的变化类型
User
托管对象,该对象与friends
关系为UserUser多对多。
现在让我们假设对于某个用户a
,2个用户x
和d
已经处于a
的朋友关系中。但是:
我将用户b
和c
添加到friends
我将d
从friends
中删除(请注意,我没有从上下文中删除对象本身,只是将其从关系中删除)
在这一点上,我想以某种方式告诉大家,对于朋友
关系:
x
没有任何更改,因为它始终存在
b
和c
在“插入集”中
d
位于“已删除集”中
或者,对于关系朋友:
b
、c
和d
有变化,并且仍然能够辨别b
和c
的变化类型为“插入”,而d
的变化类型为“删除”/“删除”
我还没有找到一个通用的方法来实现这一点。上下文已更新、插入和删除了集合,但这是上下文的集合,而不是特定关系的集合。NSManagedObject可以通过调用-(NSDictionary*)ChangedValue来为您提供有关其更改的更多信息。但不幸的是,这还不足以跟踪关系的变化。下面,我分享了我之前使用的一种技术。您应该在执行保存之前找到更改:
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];
希望这对您有所帮助。到目前为止,我提出了以下解决方案:
//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];
}]];
在这一点上,我有两个插入和删除数组(我知道,我在我的问题中说了集合…但现在它仍然有效)。
不过,我观察到的一个问题是,要使其正常工作,我需要首先从服务器检索数据,将其解析为托管对象,将这些托管对象置于适当的“默认”关系中,然后进行上下文保存。只有在上下文保存之后,changedvalue
才会反映更改,例如删除或插入的对象(如果默认情况下未插入)
现在真正的问题是上下文中的-save:
保存所有对象。因此,例如,如果我有两个实体,每个实体都有关系(即两个单独的实体,每个实体有不同的关系,我的所有示例都适用于这两个实体),如果我阅读上述代码,然后发出POST和DELETE请求,然后保存上下文,以便在此时“提交”这些对象,尝试下一步对另一个实体及其关系执行相同操作将失败,因为上下文保存会清除所有对象的更改值。在整个过程中,您是否希望在任何时候保存更改?如果不是,当在关系中没有保存更改时,考虑删除<代码> d>代码>是否有意义?Oracle存储在内存中。但在后台,托管对象是从来自服务器的json表示实例化的,并提交回服务器。这就是为什么这个例子讨论x和d对象。这个想法是x来自服务器,所以如果它被从关系中删除,我需要在friends路由上为它发出一个DELETE,否则什么都没有。对于其他对象,b和c是新的,所以我会在同一端点上为它们发布帖子。最后,d在发布之前被插入和删除,因此它不应该包含在发布到朋友的路由中。对于coredata,我可以做一个[context save:]或者不做,如果它有助于了解更改,因为它对实体JSON映射和服务器请求没有影响。顺便说一句,是的,你是对的,d被删除是没有意义的,因为我把示例搞糟了,对不起。我会改正的。基本上假设x和d都是从关系开始的。在我提交时x没有变化,d在移除集中,因为它在那里,但不再是