No se ha encontrado un model de mapeo adecuado para la migration de datos centrales.

Estoy intentando realizar una migration de datos básicos de iOS que requiere MappingModel. Los datos básicos no pueden usar el model de mapeo por alguna razón y recurre a una migration automática de peso ligero.

Habilité la opción MigrationDebug para get más información y lo que veo no tiene sentido. Los hashes de origen y de destino del model de mapeo son idénticos, ignorando el order, a los ManagedObjectModels de origen y de destino. Parece que se debe usar el model de mapeo pero el logging dice "no se encontró ningún model de mapeo adecuado".

Aquí está el logging (elided):

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: ... 

El model de mapeo generado por Xcode 4 no produce los hashes correctos necesarios para que se produzca la migration. Puede comparar el resultado del logging de migration con los hashes del file de asignación con el código siguiente:

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

Verá que estos no coinciden con los hashes en la salida del logging de migration.

La solución es generar el file de mapeo en Xcode 5.

En su método persistentStoreCoordinator, proporcione esta línea de código

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

Si esto no ayuda, entonces debes ir para la migration implementada por el usuario. Por lo tanto, tendrá que crear un model de mapeo utilizando el model de origen y destino. En ese caso set,

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

Crea dos metadatos con el siguiente código

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

e implementa la siguiente 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; } 

Después de una investigación adicional, descubrí que estaba experimentando el mismo problema que se menciona aquí (la migration de Core Data falla para la relación de uno a uno ). Configurar el mínimo a 1 lugar de no mínimo en mi relación hace que Core Data use mi model de mapeo personalizado. Aunque no estoy seguro de que suponga que este es un error en Core Data.
Sin embargo, esto me obligó a cambiar el model de mapeo original (1.0) (que los usuarios ya estaban usando) también. La solución que se me ocurrió es crear un nuevo model de mapeo entre 1.0 y 2.0 llamado 1.5. Lo único que es diferente en 1.5 en comparación con 1.0 es el mínimo de la relación, que está en 1.5 establecido en 1 . Ahora, podría permitir que Core Data realice una migration ligera de 1.0 a 1.5 y, de aquí en adelante, realice mi propia migration personalizada de 1.5 a 2.0. Aunque puede ser una solución hacky, funciona perfectamente. Pegué el código que maneja la migration a continuación.

 - (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 *infernetworkingMappingModel = [NSMappingModel infernetworkingMappingModelForSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel error:&error]; NSURL *destinationURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Migration.sqlite"]]; [migrationManager migrateStoreFromURL:storeUrl type:NSSQLiteStoreType options:nil withMappingModel:infernetworkingMappingModel 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, infernetworkingMappingModel, 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; } 

El model de mapeo probablemente no sea suficiente para manejar la migration. En este caso, el model de mapeo no se cargará, incluso si coincide con el model de origen y destino.

Escribe una testing para la migration. Vuelva a hacer los cambios a su model paso a paso y pruebe la migration. De esa forma, encontrará el cambio que impide que el model de mapeo se cargue.

Buscar: renombrar attributes o crear attributes sin especificar valores pnetworkingeterminados. Cambiar los attributes a no ser opcional.

En esos casos, debe especificar el comportamiento manualmente dentro del model de mapeo.

Tenía el mismo problema. Eliminé una entidad y cambié el nombre de los campos de relación en consecuencia. Primero traté de utilizar la migration ligera y, por lo tanto, especificé el cambio de nombre de ID para las relaciones. Debido a una supervisión mezclé los campos utilizados para el "ID de cambio de nombre" y el "Modificador de hash". Una vez corregido, todo funciona como se esperaba.