我有一个带有大型预加载数据库和小型用户数据库(均为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配置中的Entities相同。
如果我尝试进行轻量级迁移,例如:
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];
正常工作,返回适当命名的Category对象,直到取消注释第二个存储的添加为止。如果执行此操作,则获取结果返回为空。诊断性NSLog消息将完全打印我期望的内容。每个存储都与正确的配置相关联,并且每个配置都具有适当的实体。
谁能指出我的适用于多个商店设置的源代码,还是提示我做错了什么?提前致谢!
已解决:问题的症结在于在第一个代码 list 中标记为WRONG的两行。我试图以编程方式创建配置,但这似乎还不够。如果在执行此操作后查询ManagedObjectModel的配置,则和确实会看到列表中的配置,并且正确的实体已与这些配置关联。但是,似乎还需要做其他事情才能使PersistentStoreCoordinator能够正确使用它们。在Xcode中创建配置可以使它们起作用。
跟进:还有一个额外的障碍。在模拟器中设置最终的持久性存储协调器之前运行单独的迁移 channel 的解决方案非常有用。在实际设备上,权限要严格一些。如果尝试执行该迁移,则该迁移将失败,因为App捆绑包中的存储是只读的。除非您合并模型,否则似乎有必要进行迁移。如果只有一个模型,并且App捆绑包中的商店与此模型兼容,则无需迁移,并且可以使用Xcode中定义的配置进行访问。
另一个选择可能是在尝试迁移之前将数据移动到Documents目录中。我尚未证实该方法有效。
最佳答案
您是否尝试过将两个配置定义在同一模型中(即相同的模型)?您可以在编辑其中一个数据模型时选择“编辑器->添加配置”来轻松完成此操作。将UserData和ItemData的实体拖到适当的配置中。这种方式指定的配置是Core Data所遵循的。与文件/URL名称无关。完成上述操作后,请简化上面的_managedObjectModel,以在每次调用时查找单个momd文件/URL。
另外,如果您决定保留两个单独的momd文件,请确保实际上已经在模型的定义文件中分别在名为“UserData”和“ItemData”的配置中定义了模型。
我最初的建议是保留一个模型文件。除非出于某种原因这些配置不能驻留在同一对象模型中,否则将多个文件复杂化是没有意义的。我认为,将Core Data细化以完成您上面想要做的事情将是非常困难的。尝试简化代码的建模部分。