核心数据迁移问题:"持久存储迁移失败,缺少源管理对象模型."

Joh*_*her 8 migration cocoa core-data objective-c mapping-model

的背景

  • 包含两个托管对象模型的Cocoa非文档核心数据项目.
  • 模型1保持不变.模型2已更改,因此我想迁移商店.
  • 我在Xcode中通过Design> Data Model> Add Model Version创建了一个新版本.
  • 版本之间的区别是单个关系,从一个关系变为一个关系.
  • 我对模型进行了更改,然后保存了.
  • 我制作了一个新的映射模型,它将旧模型作为源,将新模型作为目标.
  • 我已经确保所有映射模型和数据模型正在编译,并且所有映射模型和数据模型都被复制到我的应用程序包的Res​​ource文件夹中.
  • 我通过在添加持久存储时使用NSMigratePersistentStoresAutomaticallyOption 密钥传入字典来启用迁移 [NSNumber numberWithBool:YES].
  • 我没有合并捆绑中的所有模型,而是指定了我想要使用的两个模型(模型1和模型2的新版本)并使用它们合并它们 modelByMergingModels:

问题

无论我做什么迁移,我都会收到错误消息:

"持久存储迁移失败,缺少源管理对象模型."

我试过的

  • 每次构建后都会清理干净.
  • 我已经尝试了各种组合,只有我在资源中迁移的模型,正在编译或两者兼而有之.
  • 由于错误消息暗示它无法找到我的迁移的源模型,因此我尝试在Resources文件夹中编译每个版本的模型.
  • 通过切换回我的数据模型的原始版本,我已经确定我没有做出一个非常基本的错误.该应用运行正常.
  • 我删除了映射模型和模型的新版本,清理后再重新创建.
  • 我尝试在新模型中进行不同的更改 - 删除实体.

我的智慧结束了.

我不禁想到我在某个地方犯了一个很大的错误,我没有看到.有任何想法吗?

Mar*_*rra 10

两种可能性:

  1. 您应用中的源模型与磁盘上的实际存储不匹配.
  2. 您的映射模型与源模型不匹配.

打开Core Data调试,您应该能够看到Core Data在进行迁移时正在寻找的哈希值.将这些哈希值与磁盘上的商店中的内容进行比较,看看它们是否匹配.同样,调试应该让您看到映射模型中的哈希值,以帮助您匹配所有内容.

如果只是您的映射模型未对齐,您可以告诉它从Xcode中的设计菜单中更新源.如果您在磁盘上缺少商店文件的实际源模型,那么您可以查看版本控制系统或尝试使用自动迁移将该文件迁移到您认为是源的模型.

更新1

更改源模型和目标模型的位置已移至编辑器窗口的底部:


ohh*_*rob 6

我没有合并捆绑中的所有模型,而是指定了我想要使用的两个模型(模型1和模型2的新版本)并使用modelByMergingModels合并它们:

这似乎不对.为何合并模型?您希望使用模型2,从模型1迁移您的商店.

来自NSManagedObjectModel类的引用

modelByMergingModels:

从现有模型数组中创建单个模型.

您不需要对源模型(模型1)执行任何特殊/特定的操作.只要它在您的包中,自动轻量级迁移过程就会发现并使用它.

我建议放弃你在XCode中创建的映射模型,因为与自动轻量级迁移相比,我看到了糟糕的性能.您的里程可能会有所不同,我的模型之间的变化与您的不同,但我不会感到惊讶.在捆绑包中使用和不使用您自己的映射模型尝试一些计时.

 /* Inferred mapping */
 NSError *error;
 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                          [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,nil];
 NSPersistentStore *migratedStore = [persistentStoreCoordinator addPersistentStoreWithType:nil
                                                                             configuration:nil
                                                                                       URL:self.storeURL
                                                                                   options:options
                                                                                     error:&error];
 migrationWasSuccessful = (migratedStore != nil);
Run Code Online (Sandbox Code Playgroud)

您可以在代码中验证您的源模型是否可用,方法是尝试加载它并验证它不是nil:

NSString *modelDirectoryPath = [[NSBundle mainBundle] pathForResource:@"YourModelName" ofType:@"momd"];
if (modelDirectoryPath == nil) return nil;
NSString *modelPath = [modelDirectoryPath stringByAppendingPathComponent:@"YourModelName"];
NSURL *modelFileURL = [NSURL fileURLWithPath:modelPath];
NSManagedObjectModel *modelOne = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelFileURL];
if (modelOne == nil) {
    NSLog(@"Woops, Xcode lost my source model");
}
else {
    [modelOne release];
}
Run Code Online (Sandbox Code Playgroud)

这假设您的项目中有一个资源" YourModelName.xcdatamodeld "和" YourModelName.xcdatamodel ".


此外,您可以检查该模型是否与现有的迁移前持久性存储兼容:

NSError *error;
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:self.storeURL error:&error];
if (storeMeta == nil) {
    // Unable to read store meta
    return NO;
}
BOOL isCompatible = [modelOne isConfiguration:nil compatibleWithStoreMetadata:storeMeta];
Run Code Online (Sandbox Code Playgroud)

该代码假定您有一个方法-storeURL来指定从中加载持久性存储的位置.