0

たとえば、User<->User 多対多の関係をUser持つ管理対象オブジェクトがあるとします。friends

aここで、2 人のユーザーが既にの関係にあるxとしましょう。しかしその後:dafriend

  1. bユーザーとcをに追加しますfriends
  2. から削除dfriendsます (コンテキストからオブジェクト自体を削除するのではなく、関係から削除するだけであることに注意してください)。

この時点で、どういうわけかfriends関係についてそれを伝えることができるようにしたいと思います:

  • xずっとあったので変化なし。
  • bc「挿入セット」に含まれています。
  • d「削除されたセット」にあります。

または、代わりに、関係の場合friends

  • bc、およびdには変更があり、 およびbc変更は「挿入」タイプであり、 の変更はd「削除」/「除去」タイプであることがわかります

これを達成するための一般的な方法はまだわかりません。コンテキストはセットを更新、挿入、および削除しましたが、それはコンテキストのためであり、特定の関係のためではありません。

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 つの配列があります (質問でセットと言いましたが、これは今のところ機能します)。私が観察した 1 つの問題は、これが機能するためには、最初にサーバーからデータを取得し、それを解析して管理対象オブジェクトに変換し、それらの管理対象オブジェクトを適切な「デフォルト」関係に配置してから、コンテキストを保存する必要があることです。コンテキストの保存後にのみchangedValues、オブジェクトの削除または挿入などの変更が反映されます (デフォルトで挿入されていない場合)。

本当の問題は-save:、コンテキストの a がすべてのオブジェクトを保存することです。したがって、たとえば、それぞれが関係を持つ 2 つのエンティティ (つまり、それぞれが異なる関係を持つ 2 つの別個のエンティティであり、すべての例が両方のエンティティに適用される) がある場合、上記のコードを実行すると、POST および DELETE 要求を発行してから、その時点でそれらのオブジェクトが「コミット」されるようにコンテキストを保存し、次に他のエンティティと同じことを行おうとすると、コンテキストの保存によってすべてのオブジェクトの changedValues がクリアされるため、その関係は失敗します。

于 2013-04-26T19:41:38.770 に答える