的背景
NSMigratePersistentStoresAutomaticallyOption
密钥作为[NSNumber
numberWithBool:YES]
传入字典来启用迁移。modelByMergingModels:
合并它们问题
无论我做什么迁移,我都会收到错误消息:
“持久存储迁移失败,缺少源管理对象模型。”
我试过的
我的智慧结束了。
我不禁想到我在某个地方犯了一个很大的错误,我没有看到。有任何想法吗?
两种可能性:
打开Core Data debugging,你应该能够看到Core Data在进行迁移时正在寻找的哈希值。将这些哈希值与磁盘上的商店中的内容进行比较,看看它们是否匹配。同样,调试应该让您看到映射模型中的哈希值,以帮助您匹配所有内容。
如果只是您的映射模型未对齐,您可以告诉它从Xcode中的设计菜单中更新源。如果您缺少磁盘上存储文件的实际源模型,则可以查看版本控制系统或尝试使用自动迁移将该文件迁移到您认为是源的模型。
更改源模型和目标模型的位置已移至编辑器窗口的底部:
我没有合并捆绑中的所有模型,而是指定了我想要使用的两个模型(模型1和模型2的新版本)并使用modelByMergingModels合并它们:
这似乎不对。为何合并模型?您希望使用模型2,从模型1迁移您的商店。
来自NSManagedObjectModel类的引用
modelByMergingModels:
从现有模型数组中创建单个模型。
您不需要对源模型(模型1)执行任何特殊/特定的操作。只要它在您的包中,自动轻量级迁移过程就会发现并使用它。
我建议放弃你在Xcode中创建的映射模型,因为与自动轻量级迁移相比,我有seen terrible performance。您的里程可能会有所不同,我的模型之间的变化与您的不同,但我不会感到惊讶。在捆绑包中使用和不使用您自己的映射模型尝试一些计时。
/* 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);
您可以在代码中验证您的源模型是否可用,方法是尝试加载它并验证它不是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];
}
这假设您的项目中有一个资源“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];
该代码假定您有一个方法-storeURL
来指定持久存储的加载位置。
在尝试升级现有应用程序的核心数据模型(并迁移旧数据)时,我遇到了第三方框架将数据写入应用程序数据库的情况。我收到此错误,“无法找到源存储的模型。”由于在尝试迁移时未加载第三方模型,因此迁移失败。
我在解决此问题时编写了此方法(如下所示)。对于那些面临这些类型问题的人来说,这可能是有用的。
- (BOOL) checkModelCompatibilityOfStoreWithURL: (NSURL *) myStoreURL
forModelNamed: (NSString *) myModelName
withBasePath: (NSString *) myBasePath;
{
NSError * error = nil;
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:myStoreURL error:&error];
if (!storeMeta) {
NSLog(@"Unable to load store metadata from URL: %@; Error = %@", myStoreURL, error);
return NO;
}
NSString * modelPath = [myBasePath stringByAppendingPathComponent: myModelName];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: modelPath]) {
// uh oh
NSLog(@"Can't find model.");
return NO;
}
NSURL * modelURL = [NSURL fileURLWithPath: modelPath];
NSManagedObjectModel * model = [[[NSManagedObjectModel alloc] initWithContentsOfURL: modelURL] autorelease];
BOOL result = [model isConfiguration: nil compatibleWithStoreMetadata: storeMeta];
NSLog(@"Tested model, %@, is%@ compatible with Database", modelPath, result ? @"" : @" ~not~");
return result;
}
此代码段将获取商店的元数据。
NSError *error = nil;
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeUrl error:&error];
NSLog(@"%@", [storeMeta objectForKey: @"NSStoreModelVersionHashes"]);
VersionInfo.plist(存储在已编译的应用程序包中)包含与模型中各种实体关联的哈希值(base64编码)。类似地,数据存储区中的BLOB列(Z_METADATA.Z_PLIST)包含二进制编码的属性列表,该列表具有与数据关联的每个实体的哈希值(也是base64编码的)。
NSManagedObjectModel上的-entitiesByName方法对于转储特定模型中存在的实体和哈希非常有用。
我遇到了类似的问题。我使用过+modelByMergeingModels:
,但我没有使用Mapping Model。但是,合并模型不适用于轻量级数据迁移。
来自Apple Docs:
要执行自动轻量级迁移,Core Data需要能够在运行时自行查找源和目标托管对象模型。
如果使用+modelByMergeingModels:
而不是用于目标模型。但是Core Data无法找到源模型。在旧版本的应用程序中使用+modelByMergeingModels:
创建了源模型,Core Data确实尝试合并模型以找出源模型。
我最终做的是我通过编辑模型的XML文件(手动)创建了一个新合并的.xcdatamodeld
,将其添加到项目中,从Compile Sources中删除了单独的.xcdatamodeld
s而不是使用+modelByMergeingModels:
使用NSManagedObjectModel
的-initWithContentsOfURL:
和URL新合并模型我可能会创建一个脚本,将来会自动合并模型。
当我收到此错误时,我更新了我的核心数据模型,但没有从我的测试手机中清除应用程序实例。这意味着保存到手机核心数据的模型与我在代码中尝试使用的模型不匹配。
我从手机中删除了应用程序并重新构建/成功运行。