找不到适合核心数据迁移的映射模型

我正在尝试执行需要MappingModel的iOS Core Data迁移。 由于某些原因,核心数据无法使用映射模型,并且会回到自动轻量级迁移。

我启用MigrationDebug选项来获取更多信息,而我所看到的是没有意义的。 映射模型的源哈希和目标哈希是相同的,忽略顺序,源和目标ManagedObjectModels。 看起来应该使用映射模型,但是日志说“找不到合适的映射模型”。

这里是(被忽略的)日志:

CoreData: annotation: (migration) will attempt automatic schema migration CoreData: annotation: (migration) looking for mapping model with source hashes: { TSBaseEntity = <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>; TSBuyer = <91e837d1 3f348913 eff634d6 6fb9b3a6 747e2390 fbdc4ae6 32cc56d6 7582d4a8>; ... } destination hashes: { TSBaseEntity = <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>; TSBuyer = <e316a857 8919c4be eef15387 5c67a21b 67d32919 99ead438 1ff93c05 2e065fcc>; ... } CoreData: annotation: (migration) checking mapping model at path file://localhost/Users/xandrews/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/0A84951E-21FC-47C0-A1B7-F880ACB672C4/Dev.app/Migrate_0_5_24To_0_5_27.cdm source hashes: {( <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>, <91e837d1 3f348913 eff634d6 6fb9b3a6 747e2390 fbdc4ae6 32cc56d6 7582d4a8>, ... )} destination hashes: {( <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>, <e316a857 8919c4be eef15387 5c67a21b 67d32919 99ead438 1ff93c05 2e065fcc>, ... )} CoreData: annotation: (migration) no suitable mapping model found CoreData: annotation: (migration) inferring a mapping model between data models with source hashes: ... 

由Xcode 4生成的映射模型不会产生迁移所需的正确哈希值。 您可以使用以下代码将迁移日志的输出与映射文件的散列进行比较:

  NSString *mappingModelPath = [[NSBundle mainBundle] pathForResource:@"MappingFile" ofType:@"cdm"]; NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:mappingModelPath]]; for (NSEntityMapping *entityMapping in mappingModel.entityMappings) { NSLog(@"%@: %@", entityMapping.sourceEntityName, entityMapping.sourceEntityVersionHash); NSLog(@"%@: %@", entityMapping.destinationEntityName, entityMapping.destinationEntityVersionHash); } 

您将看到这些与迁移日志输出中的散列不匹配。

解决方法是在Xcode 5中生成映射文件。

在你的persistentStoreCoordinator方法中给这行代码

  NSDictionary *options=[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,[NSNumber numberWithBool:YES],NSInferMappingModelAutomaticallyOption, nil]; 

如果这没有帮助,那么你需要去用户实施的迁移。 所以你将不得不使用源和目标模型创build一个映射模型。 在这种情况下,

 NSDictionary *options=[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,[NSNumber numberWithBool:NO],NSInferMappingModelAutomaticallyOption, nil]; 

用下面的代码创build双元数据

 if (sourceMetadata) { NSString *configuration = nil; NSManagedObjectModel *destinationModel = [self.persistentStoreCoordinator managedObjectModel]; //Our Source 1 is going to be incompatible with the Version 2 Model, our Source 2 won't be... BOOL pscCompatible = [destinationModel isConfiguration:configuration compatibleWithStoreMetadata:sourceMetadata]; NSLog(@"Is the STORE data COMPATIBLE? %@", (pscCompatible==YES) ?@"YES" :@"NO"); if (pscCompatible == NO) { migrationSuccess = [self performMigrationWithSourceMetadata:sourceMetadata toDestinationModel:destinationModel]; } } else { NSLog(@"checkForMigration FAIL - No Source Metadata! \nERROR: %@", [error localizedDescription]); } 

并执行以下function

 - (BOOL)performMigrationWithSourceMetadata :(NSDictionary *)sourceMetadata toDestinationModel:(NSManagedObjectModel *)destinationModel { BOOL migrationSuccess = NO; //Initialise a Migration Manager... NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:sourceMetadata]; //Perform the migration... if (sourceModel) { NSMigrationManager *standardMigrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:destinationModel]; //Retrieve the appropriate mapping model... NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:nil forSourceModel:sourceModel destinationModel:destinationModel]; if (mappingModel) { NSError *error = nil; NSString *storeSourcePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Recipes.sqlite"]; NSURL *storeSourceUrl = [NSURL fileURLWithPath: storeSourcePath]; NSString *storeDestPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Recipes2.sqlite"]; NSURL *storeDestUrl = [NSURL fileURLWithPath:storeDestPath]; //Pass nil here because we don't want to use any of these options: //NSIgnorePersistentStoreVersioningOption, NSMigratePersistentStoresAutomaticallyOption, or NSInferMappingModelAutomaticallyOption NSDictionary *sourceStoreOptions = nil; NSDictionary *destinationStoreOptions = nil; migrationSuccess = [standardMigrationManager migrateStoreFromURL:storeSourceUrl type:NSSQLiteStoreType options:sourceStoreOptions withMappingModel:mappingModel toDestinationURL:storeDestUrl destinationType:NSSQLiteStoreType destinationOptions:destinationStoreOptions error:&error]; NSLog(@"MIGRATION SUCCESSFUL? %@", (migrationSuccess==YES)?@"YES":@"NO"); } } else { //TODO: Error to user... NSLog(@"checkForMigration FAIL - No Mapping Model found!"); abort(); } return migrationSuccess; } 

经过进一步的调查,我发现我遇到了同样的问题,这里提到( 核心数据迁移失败的一对一的关系 )。 将我的关系中的最小值设置为1而不是最小值,使得Core Data使用我的自定义映射模型。 虽然我不确定我是否认为这是Core Data中的一个错误。
但是,这需要我改变原来的(1.0)映射模型(用户已经使用)。 我想到的解决scheme是创build一个1.0和2.0之间的新映射模型1.5。 与1.0相比,唯一不同的是1.5的关系的最小值,在1.5设置为1 。 现在,我可以让Core Data执行从1.0到1.5的轻量级迁移,然后执行从1.5到2.0的自定义迁移。 虽然它可能是一个hacky的解决scheme,它完美的作品。 我粘贴了处理下面的迁移的代码。

 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (persistentStoreCoordinator != nil) { return persistentStoreCoordinator; } NSURL *storeUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Project.sqlite"]]; NSError *error; NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeUrl error:&error]; if (! [[self managedObjectModel] isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) { // The current store isn't compatible with the model and should be migrated, check the version identifier of the store NSManagedObjectModel *sourceManagedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:storeMetadata]; if ([[sourceManagedObjectModel versionIdentifiers] containsObject:@"Model_1_0"]) { // The current version of the store is 1.0, a manual migration to 1.5 is needed in order to migrate finally to 2.0 NSURL *destinationModelURL = [[NSBundle mainBundle] URLForResource:@"Model.momd/Model_1_5" withExtension:@"mom"]; NSManagedObjectModel *destinationManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:destinationModelURL]; NSMigrationManager *migrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel]; NSMappingModel *inferredMappingModel = [NSMappingModel inferredMappingModelForSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel error:&error]; NSURL *destinationURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Migration.sqlite"]]; [migrationManager migrateStoreFromURL:storeUrl type:NSSQLiteStoreType options:nil withMappingModel:inferredMappingModel toDestinationURL:destinationURL destinationType:NSSQLiteStoreType destinationOptions:nil error:&error]; if (error) { DLog(@"Failed to migrate store from URL %@ with mapping model %@ to destination URL %@ with error %@", storeUrl, inferredMappingModel, destinationURL, error); } [[NSFileManager defaultManager] removeItemAtURL:storeUrl error:&error]; [[NSFileManager defaultManager] moveItemAtURL:destinationURL toURL:storeUrl error:&error]; } } NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption: [NSNumber numberWithBool:NO] }; persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) { /*Error for store creation should be handled in here*/ DLog(@"%@", error); } return persistentStoreCoordinator; } 

映射模型可能不足以处理迁移。 在这种情况下,映射模型将不会被加载,即使它与源和目标模型匹配。

写一个迁移testing。 一步一步重做对模型的更改并testing迁移。 这样你会发现阻止加载映射模型的变化。

了解:重命名属性或创build属性,而不指定默认值。 将属性更改为非可选。

在这些情况下,您必须在映射模型中手动指定行为。

有同样的问题。 我删除了一个实体,并相应地重命名了关系字段。 我第一次尝试使用轻量级迁移,因此指定关系的重命名ID。 由于疏忽,我混淆了“重命名ID”和“哈希修饰符”的字段。 一旦纠正一切都按预期工作。