11

大規模なプリロード データベースと小さなユーザー データベース (両方とも CoreData SQLite ストア) を含む iOS プロジェクトがあります。以前の質問では、構成を使用して、どのエンティティをどのストアで使用するかを制御することが提案されていました。私はそれを機能させるのに苦労しています。これが私が試してきたことです...

- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) return _managedObjectModel;
    // set up the model for the preloaded data
    NSURL *itemURL = [[NSBundle mainBundle] URLForResource:@"FlagDB" withExtension:@"momd"];
    NSManagedObjectModel *itemModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:itemURL];
    // set up the model for the user data
    NSURL *userDataURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"];
    NSManagedObjectModel *userDataModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:userDataURL];
    // merge the models
    _managedObjectModel = [NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:itemModel, userDataModel, nil]];
    // define configurations based on what was in each model
WRONG [_managedObjectModel setEntities:itemModel.entities forConfiguration:@"ItemData"];
WRONG [_managedObjectModel setEntities:userDataModel.entities forConfiguration:@"UserData"];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator;
    // preloaded data is inside the bundle
    NSURL *itemURL = [[[NSBundle mainBundle] bundleURL] URLByAppendingPathComponent:@"FlagDB.sqlite"];
    // user data is in the application directory
    NSURL *userDataURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"UserData.sqlite"];

    NSManagedObjectModel *mom = self.managedObjectModel;
    NSError *error = nil;
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];

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

これは、「ストアを開くために使用されたモデルは、ストアを作成するために使用されたモデルと互換性がありません」で中止されます。モデル内のハッシュをストア内のハッシュと照合すると、ItemData 構成内のエンティティと同じであることがわかります。

軽量の移行を試してみると、次のようになります。

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

   NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
   if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData"  URL:itemURL options:options error:&error])

「NSInvalidArgumentException」で失敗します。理由:「モデルに構成「ItemData」が含まれていません。」これは、新しいモデルが軽量の移行プロセスによって作成されているためであり、構成が含まれていないためだと思います。

他のスレッドでのいくつかの提案に基づいて、構成なしで軽量の移行を行い、構成を使用して新しいコーディネーターを作成してみました。この種の作業は、ユーザー データ エンティティ (そこに属していない) に対応するプリロードされた .sqlite ファイルにテーブルを追加し、新しく作成されたユーザー データ ストアにプリロードされたデータ テーブルとユーザー データ テーブルの両方を作成します。 . 最終結果は、フェッチが失敗することです。これは、間違ったストアを探しているためと思われます。

NSDictionary *migrationOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

// make a temp persistent store coordinator to handle the migration
NSPersistentStoreCoordinator *tempPsc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
// migrate the stores
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:itemURL options:migrationOptions error:&error])
{
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}
if (![tempPsc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:userDataURL options:migrationOptions error:&error])
{
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

// make a permanent store coordinator
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];

NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"ItemData"  URL:itemURL options:readOnlyOptions error:&error])
{
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

/*if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"UserData" URL:userDataURL options:nil error:&error])
 {
 NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 abort();
 }*/

そしてその後…

    OSAppDelegate *delegate = [UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = delegate.managedObjectContext;
    // sanity check
    for (NSPersistentStore *store in context.persistentStoreCoordinator.persistentStores) {
        NSLog(@"store %@ -> %@", store.configurationName, store.URL);
        NSMutableArray *entityNames = [[NSMutableArray alloc] init];
        for (NSEntityDescription *entity in [context.persistentStoreCoordinator.managedObjectModel entitiesForConfiguration:store.configurationName]) {
            [entityNames addObject:entity.name];
        }
        NSLog(@"entities: %@", entityNames);
    }

    NSFetchRequest *categoryFetchRequest = [[NSFetchRequest alloc] init];
    categoryFetchRequest.entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context];
    categoryFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", categoryName];
    NSError *error = nil;
    Category *category = [[delegate.managedObjectContext executeFetchRequest:categoryFetchRequest error:&error] lastObject];

2 番目のストアの追加のコメントを解除するまで、これは正常に機能し、適切な名前の Category オブジェクトを返します。そうすると、フェッチ結果は空に戻ります。診断 NSLog メッセージは、私が期待したとおりに出力されます。各ストアは正しい構成に関連付けられており、各構成には適切なエンティティがあります。

誰かが複数の店舗のセットアップのソースコードを教えてくれますか、それとも私が間違っていることを教えてくれますか? 前もって感謝します!


解決済み: 問題の核心は、最初のコード リストで WRONG とマークされた 2 行でした。プログラムで構成を作成しようとしていましたが、それでは不十分なようです。これを行った後に構成について ManagedObjectModel を照会すると、実際にリストに構成が表示され、正しいエンティティがそれらの構成に関連付けられます。ただし、PersistentStoreCoordinator がそれらを適切に使用できるようにするには、何か他のことを行う必要があるようです。Xcode で構成を作成すると、それらが機能します。


フォローアップ: 余分な障害があります。最終的な Persistent Store Coordinator を設定する前に個別の移行パスを実行するソリューションは、シミュレーターでうまく機能します。実際のデバイスでは、権限はより厳格です。その移行を行おうとすると、アプリ バンドル内のストアが読み取り専用であるため失敗します。モデルを統合しない限り、移行が必要なようです。モデルが 1 つしかなく、App バンドル内のストアがそのモデルと互換性がある場合、移行は必要なく、Xcode で定義された構成を使用したアクセスが機能します。

別のオプションとして、移行を試みる前にデータを Documents ディレクトリに移動することもできます。そのアプローチが機能することを確認していません。

4

1 に答える 1

6

同じモデル (つまり、同じ momd) で両方の構成を定義してみましたか? これは、データ モデルの 1 つを編集する際に [Editor] -> [Add Configuration] を選択することで簡単に実行できます。UserData および ItemData のエンティティを適切な構成にドラッグします。このように指定された構成は、Core Data が尊重するものです。ファイル/URL名に関するものではありません。上記を実行したら、上記の _managedObjectModel を単純化して、呼び出されるたびに単一の momd ファイル/URL を検索します。

または、2 つの別個の momd ファイルを保持することにした場合は、モデル定義ファイルでそれぞれ「UserData」および「ItemData」という名前の構成でモデルを実際に定義したことを確認してください。

私の最初の提案は、1 つのモデル ファイルを保持することです。これらの構成を同じオブジェクト モデルに配置できない理由がない限り、複数のファイルで複雑にすることは意味がありません。あなたが上でやろうとしていることをコアデータを巧みに実行するのは非常に難しいと思います. コードのモデリング部分を単純化するようにしてください。

于 2012-04-21T00:25:57.927 に答える