0

例如,假设我有一个User托管对象,其friends关系是用户<->用户多对多。

现在让我们说一些用户a,2 个用户x并且d已经在a' 的friend关系中。但是之后:

  1. 我将用户添加b到.cfriends
  2. 我从中删除dfriends请注意,我不会从上下文中删除对象本身,只是将其从关系中删除)。

在这一点上,我想以某种方式能够说明这种friends关系:

  • x没有任何变化,因为它一直在那里。
  • b并且c在“插入集”中。
  • d位于“已删除集”中。

或者,对于关系friends

  • b, c, andd有变化,并且仍然能够分辨bandc的变化是“插入”类型,而d's 是“删除”/“删除”类型

我还没有想出一个通用的方法来实现这一点。上下文已更新、插入和删除集合,但这是针对上下文的,而不是针对特定关系的。

4

2 回答 2

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];

希望这对您有所帮助。

于 2013-04-26T11:32:51.370 回答
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:上下文中的 a 保存了所有对象。因此,例如,如果我有 2 个实体,每个实体都有关系(即 2 个独立的实体,每个实体都有不同的关系,我的所有示例都适用于这两个实体),如果我通过上面的代码,然后发出 POST 和 DELETE 请求,然后保存上下文,以便此时这些对象被“提交”,尝试下一步对另一个实体执行相同操作,并且它的关系将失败,因为上下文保存清除了所有对象的 changedValues。

于 2013-04-26T19:41:38.770 回答