17

2つの別々の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();
    }
4

4 に答える 4

9

WWDC 2012ラボに参加し、Core Dataチームとミーティングを行った後、すべてのモデル情報を1つのxcdatamodelに入れる必要があるようです。CoreDataは、CoreDataを作成し、まだディスク上にあるストアの組み合わせとして、既存のストアをチェックするほどインテリジェントではありません。C. Roaldが指摘したように、古いxcdatamodelファイルに対していくつかの処理を行うことができますが、CoreDataがこれをよりエレガントに処理しないのは非常に悲しいことです。

于 2012-12-13T02:41:09.780 に答える
8

私もこの問題に遭遇しました。私はWTFを理解しようとして数時間を失いました-非常にイライラします。

この問題を解決する最も簡単な方法は次のとおりです。

  1. 保持しているモデル(たとえばModelB)を選択し、公開されているバージョンに基づいて新しいバージョンを作成します。公開バージョンをModelBv1と呼び、新しいバージョンをModelBv1_mergeと呼びます。

  2. ModelAv1およびModelBv1_mergeのコンテンツXMLファイルをテキストエディター(つまり、ModelA.xcdatamodeld/ModelAv1.xcdatamodel/contentsおよびModelB.xcdatamodeld/ModelBv1_merge.xcdatamodel/contents)で開き、XMLを手動でマージします。スキーマは非常に単純です。要素をコピーして要素を(_mergeコンテンツファイルに)<entity>マージするだけで完了です。<elements>

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

  4. プロジェクトファイルからModelAを削除します。

Xcodeで、ModelBv1_mergeとModelBv2が正常に見え、期待するすべてのものが含まれていることを確認します(古いモデルAとモデルBの結合)。ビルドすれば完了です。

(これには「両方のコンテンツファイルが同じバージョンのXcodeで記述されている場合」という警告があると思いますが、古いコンテンツファイルがある場合は、どこかで些細な変更を加えるだけでXcodeに書き換えさせるのは簡単だと思います。 )。

于 2012-12-07T00:11:52.490 に答える
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);
}
于 2014-06-10T15:43:40.220 に答える
0

Core Dataモデルをアップグレードする最良の方法は、バージョンを追加することです。そうしないと、クラッシュで死に、危険を更新し、そのようなものになります。

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

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

お役に立てれば。

于 2012-06-18T15:22:57.783 に答える