核心数据 – 轻量级迁移和多核心数据模型文件(xcdatamodel)

从两个单独的xcdatamodel文件定义的存储迁移时,执行轻量级迁移时遇到问题。

在我的应用程序的1.0版中,我将模型分解为分析模型,模型-A和模型-B中的所有其他模型。 编译时,模型将被分组在一起,一切进展顺利。

在使用新版本1.1时,我通过向模型B添加新模型版本并将新版本设置为活动状态来升级模型B.

从1.0升级到1.1时出现问题。 看来Core Data检查磁盘上的模型存储(由版本1.0创build),并寻找描述它的模型,但无法find定义整个商店的SINGLE模型(模型-A仅涵盖分析,模型-B覆盖一切),所以它会抛出一个“无法find源存储模型”的错误。

有没有人find一个解决scheme来分离模型,但仍然允许升级+轻量级迁移工作,没有定义自定义迁移额外的麻烦?

以下是用于加载模型的代码片段:

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

我也遇到过这个问题。 我花了几个小时试图找出WTF – 非常令人沮丧。

我相信解决这个问题最简单的方法是:

  1. select您保留的模型 – 例如ModelB – 并根据发布的版本为其创build新版本。 我将调用发布的版本ModelBv1和新版本ModelBv1_merge。

  2. 在文本编辑器(即ModelA.xcdatamodeld/ModelAv1.xcdatamodel/contentsModelB.xcdatamodeld/ModelBv1_merge.xcdatamodel/contents )中打开ModelAv1和ModelBv1_merge的内容XML文件并手动合并XML。 模式非常简单 – 只需复制<entity>元素并合并<elements>元素(到_merge内容文件中),就完成了。

  3. 打开新的ModelBv2的内容文件并再次将ModelA内容合并到其中。

  4. 从您的项目文件中删除ModelA。

检查Xcode ModelBv1_merge和ModelBv2看起来是否理智,并包含您期望的所有内容(旧的模型A和模型B的联合)。 build立,你应该完成。

(我认为这里提供了一个告诫,“提供的内容文件是由相同版本的Xcode编写的”,但是我认为如果你有一个旧的内容文件,应该很容易让Xcode通过在某个地方做一个微小的改变来重写它。 )

参加WWDC 2012实验室并与Core Data团队会面后,似乎您不得不将所有模型信息放在一个xcdatamodel中。 CoreData的智能不足以将其现有商店作为创build它的商店的组合,并且仍在磁盘上。 正如C. Roald指出的那样,你可以在旧的xcdatamodel文件上做一些处理,但是Core Data并没有更好地处理这个问题,这真是令人伤心。

我有一个场景,我的应用程序模型获得合并多个模型,我设法有一种自动轻量级迁移这种方式:

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

升级核心数据模型的最好方法是添加一个版本。 如果你不这样做,你将会崩溃,更新危险和类似的东西。

添加一个新版本其实很简单。 您select数据模型文件并select“编辑器>添加模型版本”。 这将使您能够添加基于前一个模型的新数据库版本。 然后您需要将当前的数据模型设置为最新的: http : //cl.ly/2h1g301b0N143t0b1k2K

在安装新版本时,iOs会自动迁移数据(至less在我的情况下)。

希望这可以帮助。