I\'m trying to perform an iOS Core Data migration that requires a MappingModel. Core data is not able to use the mapping model for some reason and it falls back to an automa
After futher investigation I found out I was experiencing the same issue as mentioned here (Core Data migration fails for to-one relationship).
Settings the minimum to 1
instead of no minimum in my relationship made Core Data use my custom mapping model. While I'm not sure I assume this is a bug in Core Data.
However, this required me to change the original (1.0) mapping model (which users were already using) too.
The fix I came up with is to create a new mapping model between 1.0 and 2.0 called 1.5. The only thing that's different in 1.5 in comparison with 1.0 is the minimum of the relationship, which is in 1.5 set to 1
.
Now, I could let Core Data perform a lightweight migration from 1.0 to 1.5 and hereafter perform my own custom migration from 1.5 to 2.0.
Although it may be a hacky solution, it works perfectly. I pasted the code that handles the migration below.
- (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;
}