2012-06-07 6 views
16

2つの別々のxcdatamodelファイルで定義されたストアから移行するときに軽量移行を実行する際に問題が発生します。コアデータ - 軽量移行と複数のコアデータモデルファイル(xcdatamodel)

私のアプリのバージョン1.0では、モデルはアナリティクスモデル、モデル-A、およびモデル-Bのその他すべてに分けられました。コンパイルすると、モデルはグループ化され、すべてがスムーズに進行しました。

新しいバージョン1.1で作業しているときに、モデルBに新しいモデルバージョンを追加し、その新しいバージョンをアクティブとして設定することでモデルBをアップグレードしました。

1.0から1.1にアップグレードするときに問題が発生します。 Core Dataはモデルストアをディスク上でチェックし(バージョン1.0で作成)、それを記述するモデルを探しますが、ストア全体を定義するSINGLEモデルを見つけることはできません(モデルAは解析のみをカバーし、モデルBはカバーそれ以外はすべて)、「ソースストアのモデルが見つかりません」というエラーがスローされます。

モデルを分離するためのソリューションが見つかりましたが、カスタムマイグレーションを定義する追加の手間をかけずにアップグレード+軽量移行が可能です。ここで

はモデルをロードするために使用されるコードの抜粋です:

NSArray *modelNames = [NSArray arrayWithObjects:@"model-A", @"model-B", nil]; 
    NSMutableArray *models = [NSMutableArray array]; 
    for (NSString *name in modelNames) 
    { 
     LogInfo(@"loading model %@", name); 
     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:name withExtension:@"momd"]; 
     NSManagedObjectModel *model = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] autorelease]; 
     [models addObject:model]; 
    } 

    // combine all the separate models into one big one 
    objectModel = [[NSManagedObjectModel modelByMergingModels:models] retain]; 

    NSURL *documentsDirectory = [NSURL fileURLWithPath:[SuperFileManager documentsDirectory] isDirectory:YES]; 
    NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"database.sqlite"]; 
    NSError *error = nil; 

    coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel]; 
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
                [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, 
                nil]; 

    if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType 
            configuration:nil 
              URL:storeURL 
             options:options 
              error:&error]) 
    { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 

答えて

8

WWDC 2012ラボに出席し、コアデータチームと出会った後、すべてのモデル情報を1つのxcdatamodelに入れなければならないようです。 CoreDataは、既存のストアを作成し、まだディスク上にあるストアの組み合わせとして、既存のストアをチェックするのに十分なインテリジェントではありません。 C. Roald氏によると、古いxcdatamodelファイルについてはいくつかの処理を行うことができますが、コアデータがこれをよりうまく処理できないことは非常に悲しいことです。

+0

これに関する最新情報はありますか? – codepushr

+0

@codingrogue - 残念ながら。私が当時取り組んでいたチームは、コアデータを使用して放棄し、私はAndroidプログラミングに切り替えました。ごめんなさい。 :/ – Mark

0

あなたのコアデータモデルをアップグレードするための最良の方法は、バージョンを追加することです。あなたがそれをしないと、あなたはクラッシュで滅び、危険を更新し、そのようなことをします。

新しいバージョンを追加することは、実際には非常に簡単です。データモデルファイルを選択し、「エディタ>モデルバージョンを追加」を選択します。これにより、以前のモデルに基づいて新しいデータベースバージョンを追加することができます。現在のデータモデルを最新のものに設定する必要があります。http://cl.ly/2h1g301b0N143t0b1k2K

新しいバージョンがインストールされると、iOsはデータを自動的に(少なくとも私の場合は)マイグレーションします。

これが役に立ちます。

+3

あなたは、単一のxcdatamodelを持っているとき、これが正常に動作します。複数ある場合、それらの1つをアップグレードすると、コアデータは物事を調整できません。 WWDC 2012ラボに参加した後は、基本的にすべてのモデル情報を1つのxcdatamodelに入れておきましょう。 – Mark

8

この問題も発生しました。私はWTFを理解しようと数時間を失った - 非常にイライラ。 ModelBを言う - - あなたは維持しているモデル

  1. ピックはと公開バージョンに基づいて、それのための新しいバージョンを作成します。

    私はこの問題を解決するための最も簡単な方法があると信じています。私は出版されたバージョンModelBv1と新しいバージョンModelBv1_mergeを呼びます。

  2. XMLをModelAv1とModelBv1_mergeのXMLファイルをテキストエディタ(ModelA.xcdatamodeld/ModelAv1.xcdatamodel/contentsModelB.xcdatamodeld/ModelBv1_merge.xcdatamodel/contents)で開き、XMLを手作業でマージします。スキーマは非常にシンプルです。<entity>要素をコピーし、<elements>要素を(_mergeコンテンツファイルに)マージすると完了です。

  3. 新しいModelBv2のコンテンツファイルを開き、ModelAのコンテンツを再度そのファイルにマージします。

  4. プロジェクトファイルからModelAを削除します。 ModelBv1_mergeとModelBv2は正気見て、あなたが期待するすべてのもの(旧モデルAとモデルBの和集合)を含有してXcodeで

チェック。ビルドしてやる必要があります。

(これは「両方のコンテンツファイルが同じバージョンのXcodeで作成されている」という警告があると思いますが、古いコンテンツファイルをお持ちの場合、Xcodeで)

+0

Hacktasticの方法では、2つのデータモデルファイルを保持することができます(一時的な場合でも!ありがとう!) – Mark

+0

驚くばかりです。私のベーコンを救った。おかげで – Darren

+0

こんにちは、この方法は素晴らしいシミュレータで動作していますが、デバイスで動作していないのですか? –

5

私は自分のアプリケーションモデルは、複数のモデルをマージ取得し、私はこのように自動軽量の移行のようなものを持っているように管理されるシナリオがあります。

NSError* error = nil; 
NSURL *documentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"db.sqlite"]; 
NSString* storePath = [storeURL path]; 
NSLog(@"Store URL: %@", storeURL); 
if([[NSFileManager defaultManager] fileExistsAtPath:storePath]){ 
    // Load store metadata (this will contain information about the versions of the models this store was created with) 
    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeURL error:&error]; 
    if(storeMeta){ 
     // Get the current model, merging all the models in the main bundle (in their current version) 
     NSManagedObjectModel* model=[NSManagedObjectModel mergedModelFromBundles:nil]; 
     // If the persistent store is not compatible with such a model (i.e. it was created with a model obtained merging old versions of "submodels"), migrate 
     if(![model isConfiguration:nil compatibleWithStoreMetadata:storeMeta]){ 


      // Load the old model 
      NSManagedObjectModel*oldModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:storeMeta]; 

      // Compute the mapping between old model and new model 
      NSMappingModel* mapping = [NSMappingModel inferredMappingModelForSourceModel:oldModel destinationModel:model error:&error]; 
      if(mapping){ 
       // Backup old store 
       NSURL* storeBackupURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:@"db.sqlite.%@.bck", [NSDate new]]]; 
       BOOL done = [[NSFileManager defaultManager] moveItemAtURL:storeURL toURL:storeBackupURL error:&error]; 
       if(done){ 
        // Apply the mapping 
        NSMigrationManager* migrationManager = [[NSMigrationManager alloc] initWithSourceModel:oldModel destinationModel:model]; 
        BOOL done = [migrationManager migrateStoreFromURL: storeBackupURL 
                   type: NSSQLiteStoreType 
                   options: nil 
                withMappingModel: mapping 
                toDestinationURL: storeURL 
                 destinationType: NSSQLiteStoreType 
                destinationOptions: nil 
                   error: &error]; 
        if(done){ 
         NSLog(@"Store migration successful!!!"); 
        } 
       } 
      } 
     } 
    } 
} 

if(error){ 
    NSLog(@"Migration error: %@", error); 
} 
+0

あなたの返信を読む前に、私は自分自身がこのコードを書いていることを発見しました。醜いですが、これはこれを行う唯一の方法のようです。 –

+0

うわー、ありがとう、私は何時間もこの問題に立ち往生している。ただ1つの質問、あなたはすべてのバックアップファイルを保管していますか?私は、マイグレーションが完了したら、それらを削除することに害はないと推測している – Leonardo

+0

これは本当に私のお尻を保存したうわー。本当にありがとう!!私の具体的な問題は、従来のアプリケーションから手動で移行するための古いxcdatamodeldと、バージョン管理された新しいxcdatamodeldを作成したことです。私はコアデータがこれを窒息していたと思います。 –

関連する問題