I'm trying to migrate to a new completely different model in my project. The changes are way too much for a lightweight migration and I think the best way is to iterate through the top level objects and set all the attributes and relationships myself.
How can I set up the migration process to be completely manual like this. I've looked into NSMigrationManager which seems to require an NSMappingModel. The only examples and tutorials I've seen use inferredMappingModelForSourceModel:destinationModel:error:
which I can't use because it isn't able to infer the mapping model.
Am I on the right path and if so how can I create a mapping model completely manually in code? Thanks for the help.
If your model changes are such that you at least have an source and destination entity level mapping (For example you had a Vehicle
entity in your old model and now you want to migrate that data to Car
) then you can use a custom mapping model with a migration policy.
The process is fairly straightforward, in Xcode, try to add a new mapping model file to your project, select the source model version and destination model version. Xcode tries to be smart about figuring out the mapping between attributes of your source and destination entities. If it isn't able to, it'll just leave the mappings blank and you can set your own mapping.
If you'd like to do something other than simple assignment or blanking out or setting a default value for attributes during mapping, use something called an NSEntityMigrationPolicy
. Create your own subclass and implement this method to do your custom mapping:
- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)instance
entityMapping:(NSEntityMapping *)mapping
manager:(NSMigrationManager *)manager
error:(NSError **)error {
NSArray *_properties = [mapping attributeMappings];
for (NSPropertyMapping *_property in _properties) {
if ([[_property name] isEqualToString:@"companyName"]) {
NSExpression *_expression = [NSExpression expressionForConstantValue:@"10to1"];
[_property setValueExpression:_expression];
}
}
return [super createDestinationInstancesForSourceInstance:instance
entityMapping:mapping
manager:manager
error:error];
}
You can read more about how to do a custom migration here.
Check out CDWrangler. It's an open source Core Data controller that can handle lightweight and manual migration progressively.
After you create your mapping model, and any custom policies you need you just need to do this
// Migration
if ([[CDWrangler sharedWrangler] isMigrationNeeded]) {
// The key is the name of your starting model, and the value is the name of your mapping model. In this example they are Model.xcdatamodel and MappingModel.xcmappingmodel
[CDWrangler sharedWrangler].mappingsForModels = @{@"Model": @"MappingModel"};
[[CDWrangler sharedWrangler] migrate];
}