3

CoreDataで次の関係を想像してみてください

Recipe < --- >> Ingredient

MagicalRecordを使用して、ローカルCoreDataデータベースでサーバーデータベース(JSON API)を定期的にインポートしています。

したがって、次のようにインポートRecipe 1すると、Ingredient 1次のようになります。

{
  id:1,
  name: "Recipe 1",
  ingredients: [{
    name: 'Ingredient 1'
  }]
}

つまり、MagicalRecordは2つのエンティティを作成し、それらをリンクします。

サーバーが次のように変更されると、問題が発生します。

{
  id:1,
  name: "Recipe 1",
  ingredients: [{
    name: 'Ingredient 2' <-- Notice here
  }]
}

MagicalRecordが行うことは、Ingredient 2レコードを作成し(正しい)、それをリンクして(正しい)唯一の要素にすることRecipe 1です。しかし、Ingredientsを検索すると、CoreDataデータベースに2つのレコードが見つかりました。

質問は、インポートおよび削除時に「削除された」オブジェクトを追跡することは可能ですか?

4

3 に答える 3

1

このプロセスに従って、この問題を回避しました。

  1. コア データ ストアに対してクエリを実行すると、特定のサーバー リクエストに対して期待される値が返されます。サーバーによって返されると予想されるクエリによって検出されたすべてのオブジェクトのすべての objectID を検索します。
  2. サーバー リクエストを作成し、データをインポートします。
  3. 保存する前に、データのインポートに使用したコンテキストから更新されたすべてのオブジェクトを取得します。
  4. 更新された objectID のリストにない objectID の元のリスト内のオブジェクトを削除します

このアプローチは、特定のリクエストに対して望ましい動作を実現する必要があります。他の場所から参照されているレコードを削除する可能性があることに注意してください。したがって、他の将来のリクエストによって再作成できる場合にのみ、このアプローチを使用してください。

コードのインポート

NSArray *existingObjectIDs = [self existingObjectIDsForYourQuery];

[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
                    [Recipe MR_importFromObject:response inContext:localContext];
                    NSArray *objectIDs = [[[localContext updatedObjects] allObjects] valueForKey:@"objectID"];
                    [self deleteLocalObjectsWithObjectIDs:existingObjectIDs excludingImportedObjectIDs:objectIDs];
}];

コードを削除

- (void)deleteLocalObjectsWithObjectIDs:(NSArray *)existingObjectIDs excludingImportedObjectIDs:(NSArray *)importedObjectIDs {
    NSMutableArray *objectsToDelete = [NSMutableArray arrayWithArray:existingObjectIDs];

    for ( NSManagedObjectID *objectID in importedObjectIDs ) {
        [objectsToDelete removeObject:objectID];
    }

    [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {
        for ( NSManagedObjectID *objectID in objectsToDelete ) {
            NSManagedObject *object = [localContext existingObjectWithID:objectID error:nil];

            if ( object ) {
                [localContext deleteObject:object];
            }
        }
    }];
}
于 2014-05-14T02:38:36.237 に答える
1

ここでの本当の問題は、MagicalRecord が重複をインポートしているように見えることです。この問題は最近のアップデートで解決されているはずですが、まだ問題がある場合は、プロジェクトの問題ページでチケットを開くことをお勧めします

于 2012-07-23T14:15:39.183 に答える
0

Ingredientこれが主キーとして使用している場合、サーバー上の名前を変更することはできません。MagicalRecord と Core Data は、どのレコードが更新されたかを知る手がかりがありません。わかっているのはIngredient、その名前のレコードが存在しないことだけであり、新しいレコードを作成して から関係をマッピングしますRecipe。JSON ペイロードに存在しないローカル アプリ データベースのレコードは、手動で削除する必要があります。

次の点を考慮してください。

Ingredientオブジェクトの主キーがありません。どのキーがプライマリであるかを MagicalRecord に知らせる必要があります (「ingredientID」属性が存在しない場合)。

これを行うには、Core Data モデルに入り、Ingredientエンティティを選択します。次に、データ モデル インスペクターのユーザー情報に "relatedByAttribute" キーを追加します。値は "name" です。

次にRecipeエンティティに移動し、関係を選択して、関係Ingredientのユーザー辞書に「relatedByAttribute」キーと「name」値を追加します。このようにして、MagicalRecordIngredientは「name」属性によって既存のレコードを検索することを認識し、存在する場合は既存のレコードにマップし、他のレコードは新しいエンティティを作成してそれにリンクRecipeします。

ここで詳細情報を読むことができます: http://www.cimgf.com/2012/05/29/importing-data-made-easy/、特に「Related by keys」セクションに興味があります。

繰り返しますが、上記のように、名前を更新しただけです。つまりIngredient、現在の のすべての を削除する必要がありますRecipe。サーバー上のオブジェクトを削除する場合は、ローカル データベースでも削除する必要があります。

Recipeそれでも問題が解決しない場合は、名前に一致するレコードを手動で検索し、それに応じて作成/更新するカテゴリ クラスを作成することをお勧めします。ただし、ペイロードには存在しないがローカルに存在するレコードを削除することを忘れないでください。

于 2013-02-09T14:47:57.580 に答える