CoreData与多个商店:configuration的困境

我有一个大型的,预加载的数据库和一个小型用户数据库(CoreData SQLite商店)的iOS项目。 先前的问题已经build议使用configuration来控制哪个实体与哪个商店一起使用。 我无法正常工作。 这是我一直在尝试…

- (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(); } ... 

这会中止“用于打开商店的模型与用于创build商店的模型不兼容”。 检查模型中的散列与存储中的散列,显示它们与ItemDataconfiguration中的实体相同。

如果我尝试做一个轻量级的迁移,像这样:

  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'失败,原因:'模型不包含configuration'ItemData'。 我认为这是因为轻量级迁移过程正在创build一个新模型,并且不包含我的configuration。

基于其他线程中的一些build议,我已经尝试做一个没有configuration的轻量级迁移,然后使用configuration创build一个新的协调器。 这种工作,但是它将表格添加到与用户数据实体(不属于那里)相对应的预加载的.sqlite文件中,并在新创build的用户数据存储中创build预加载的数据表和用户数据表。 最终的结果是提取失败,看起来是因为他们在错误的商店。

 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]; 

这工作正常,返回适当名称的类别对象,直到我取消了第二家店的增加注释。 如果我这样做,取回结果回来空。 诊断NSLog消息正好打印我所期望的。 每个商店都与正确的configuration相关联,并且每个configuration都有适当的实体。

任何人都可以指出我的源代码工作多商店设置,或线索我,我做错了什么? 提前致谢!


解决 :问题的关键是在第一个代码清单中标记为“错误”的两行。 我试图以编程方式创buildconfiguration,但似乎是不够的。 如果您在执行此操作后查询ManagedObjectModel以进行configuration, 确实可以看到列表中的configuration,并且正确的实体与这些configuration相关联。 但是,似乎还需要做一些其他事情来使PersistentStoreCoordinator能够正确使用这些内容。 在Xcode中创buildconfiguration使它们工作。


后续 :有一个额外的障碍。 在设置最终的永久存储协调器之前运行单独的迁移通道的解决scheme在模拟器中工作得非常好。 在实际的设备上,权限更为严格。 如果您尝试执行迁移,则失败,因为应用程序包中的存储区是只读的。 除非您整合模型,否则移植似乎是必要的。 如果您只有一个模型,并且App包中的商店与其兼容,则迁移不是必需的,并且使用Xcode中定义的configuration进行访问。

另一个选项可能是在尝试迁移之前将数据移动到Documents目录中。 我还没有证实这种方法是有效的。

你有没有试过在同一个模型(即相同的妈妈)定义的两个configuration? 编辑其中一个数据模型时,您可以通过select“编辑器 – >添加configuration”轻松完成此操作。 将UserData和ItemData的实体拖动到适当的configuration中。 以这种方式指定的configuration是Core Data所尊重的; 这不是关于文件/ URL的名称。 一旦你完成上述,然后简化你的_managedObjectModel以查找单一的妈妈文件/ URL每当它被调用。

或者,如果您决定保留两个独立的momd文件,请确保您已在模型定义文件中分别在名为“UserData”和“ItemData”的configuration中实际定义了模型。

我最初的build议是保留一个模型文件。 除非这些configuration不能存在于同一个对象模型中,否则将多个文件复杂化是没有意义的。 我认为将Core Data转化为上面提到的做法是相当困难的。 尝试简化代码的build模部分。

Interesting Posts