10

開発中のアプリでは、Core Data と sqlite バッキング ストアを使用してデータを保存しています。アプリのオブジェクト モデルは複雑です。また、アプリによって提供されるデータの総量が大きすぎて、iOS (iPhone/iPad/iPod Touch) アプリ バンドルに収まりません。通常、ユーザーはデータのサブセットのみに関心があるため、アプリがデータ オブジェクトのサブセット (最大 100 MB) を含むようにデータを分割しました。アプリバンドル。ユーザーは、iTunes のアプリ内購入を通じて追加コンテンツの料金を支払った後、サーバーから追加のデータ オブジェクト (サイズが ~5 MB から 100 MB) をダウンロードするオプションがあります。増分データ ファイル (sqlite バッキング ストアに存在する) は、バンドルに同梱されるデータと同じ xcdatamodel バージョンを使用します。オブジェクト モデルへの変更はありません。増分データ ファイルは、サーバーから gzip 圧縮された sqlite ファイルとしてダウンロードされます。増分コンテンツをアプリと一緒に出荷することで、アプリ バンドルを肥大化させたくありません。また、Web サービスを介したクエリに依存したくありません (複雑なデータ モデルのため)。サーバーからの増分 sqlite データのダウンロードをテストしました。ダウンロードしたデータ ストアをアプリの共有の persistentStoreCoordinator に追加できました。  

{
       NSError *error = nil;
       NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

       if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:defaultStoreURL options:options error:&error])
       {            
           NSLog(@"Failed with error:  %@", [error localizedDescription]);
           abort();
       }    

       // Check for the existence of incrementalStore
       // Add incrementalStore
       if (incrementalStoreExists) {
           if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:incrementalStoreURL options:options error:&error])
           {            
               NSLog(@"Add of incrementalStore failed with error:  %@", [error localizedDescription]);
               abort();
           }    
       }
 }

  ただし、この方法で行うには 2 つの問題があります。

  1. データ フェッチの結果 (NSFetchResultController などを使用) は、defaultStoreURL のデータの末尾に追加された incrementalStoreURL のデータと共に表示されます。
  2. 一部のオブジェクトが複製されています。私たちのデータ モデルには、読み取り専用データを持つエンティティが多数あります。これらは、2 番目の persistentStore を persistentStoreCoordinator に追加すると複製されます。

理想的には、Core Data が 2 つの永続ストアからのオブジェクト グラフを 1 つにマージすることを望みます (データのダウンロード時に、2 つのストアからのデータ間に共有関係はありません)。また、重複したオブジェクトを削除したいと考えています。Web を検索すると、この回答この回答など、私たちが行っているのと同じことをしようとしている人々によるいくつかの質問が見つかりました。Core Data での大規模なデータ セットのインポートに関する Marcus Zarra のブログを読みました。しかし、これまで見てきた解決策はどれもうまくいきませんでした。インクリメンタル ストアからデフォルト ストアにデータを手動で読み取って保存することは、電話では非常に遅く、エラーが発生しやすいと考えられるため、行いたくありません。マージを行うより効率的な方法はありますか?

次のように手動移行を実装することで、問題の解決を試みました。ただし、マージを成功させることはできませんでした。上記の回答 1 と 2 で提案されている解決策については、明確ではありません。Marcus Zarra のブログでは、大規模なデータセットを iOS にインポートするプロジェクトの開始時に発生した問題のいくつかに対処しました。

{
       NSError *error = nil;
       NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];        

       NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:__managedObjectModel destinationModel:__managedObjectModel];
       if (![migrator migrateStoreFromURL:stateStoreURL
                                type:NSSQLiteStoreType 
                             options:options 
                    withMappingModel:nil
                    toDestinationURL:destinationStoreURL 
                     destinationType:NSSQLiteStoreType 
                  destinationOptions:nil 
                               error:&error])
       {
           NSLog(@"%@", [error userInfo]);
           abort();
       }
}

  回答 1 の作成者は、最終的にインクリメンタル ストアからデータを読み取り、デフォルト ストアに保存したようです。おそらく、記事 1 と 2 の両方で提案されている解決策を誤解している可能性があります。データのサイズによっては、増分データを手動で読み取って既定のストアに再挿入することができない場合があります。私の質問は、オブジェクト グラフを (同じ objectModel を持つ) 2 つの PersistentStore から取得して 1 つの PersistentStore にマージする最も効率的な方法は何ですか?

自動移行は、新しいエンティティ属性をオブジェクト グラフに追加したり、関係を変更したりするときに非常にうまく機能します。自動移行が行われるため、同様のデータを停止して再開するのに十分な回復力を持つ同じ永続ストアにマージする簡単なソリューションはありますか?

4

3 に答える 3

1

移行が機能しない理由は、マネージド オブジェクト モデルが同一であるためです。

技術的には、「スキーマの移行」ではなく「データの移行」について話しているのです。CoreData の移行 API は、マネージド オブジェクト モデルへの変更を処理するスキーマ移行用に設計されています。

あるストアから別のストアにデータを転送する限り、あなたは一種のものです。CoreData は、フェッチ リクエストでバッチ処理とフェッチ制限を使用することで効率を高めるのに役立ちますが、ロジックを自分で実装する必要があります。

大きな店舗と小さな店舗の 2 つの永続的な店舗があるようですね。小さなストアをロードして分析し、大きなストアで照会する必要がある主キーまたは一意の識別子のセットを見つけるのが最も効率的です。

これらの識別子について、より大きなストアにクエリを実行するだけで、簡単に重複除外できます。

NSFetchRequest のドキュメントには、クエリのスコープを設定するための API があります。

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/NSFetchRequest.html

于 2012-04-02T05:00:26.433 に答える
1

移行は必要ありません。移行は、データ自体ではなく、NSManagedObjectModel に変更をもたらすように設計されています。

本当に必要なのは、2 つの永続ストアを管理する永続ストア コーディネーターです。ちょっとトリッキーですが、それほど難しいことではありません。

あなたが本当に何をする必要があるかを説明できる同様の質問があります。 相互の関係を維持しながら、複数 (2 つ) の永続ストアを 1 つのオブジェクト モデルで使用できますか?

これはマーカス・ザラによる良い記事です

http://www.cimgf.com/2009/05/03/core-data-and-plug-ins/

于 2012-04-03T08:10:24.347 に答える