Here is the core data diagram for before:
And after:
So I basically added 1 new entity called Category and some new attributes.
According to apple docs, in order for me to merge these two different version of my data model, I would need to perform a lightweight migration. Adding attributes or entities can usually be done using lightweight migrations.
I wanted to make sure that the existing data would not be overwritten and that the list of restaurants and dishes would just be moved to a category called Restaurants.
The following is a step by step list of what I had to do to complete this successfully. There are many examples of the first few steps on the internet already, the last few steps are specific to my data.
Create a new database model version:
1. Click on my database .xcdatamodeld file in project navigator2. Go to Editor in menu bar, and select Add Model Version...
3. Name the version of data model, I used TastebankVer2 and hit Finish
4. A little green arrow shows which version of the data model is currently being used, to make the new version the current active version, you click on the data model you just added, then go to utilities->Model Version->select current version in drop down list
Add code to enable lightweight migration:
1. Open App delegate file
2. Go to addPersistentStoreWithType:configuration:URL:options:error: method
Apple's suggested code shows:
NSError *error = nil; |
NSURL *storeURL = <#The URL of a persistent store#>; |
NSPersistentStoreCoordinator *psc = <#The coordinator#>; |
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: |
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, |
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; |
BOOL success = [psc addPersistentStoreWithType:<#Store type#> |
configuration:<#Configuration or nil#> URL:storeURL |
options:options error:&error]; |
if (!success) { |
// Handle the error. |
} |
Here is my persistentStoreCoordinator code:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSError *error = nil;
NSURL *storeURL =
[[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"TasteB.sqlite"];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel: [self managedObjectModel]];
BOOL success = [ _persistentStoreCoordinator
addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeURL
options:@{NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES} error:&error];
if (!success) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
At this point the lightweight migration is activated and should work right away for adding attributes and stuff.
Copy old data into new structure
However I also wanted my existing data restructured. I already had a list of restaurants and dishes in the old version of my app.
---------->
When moving to the new version, I wanted all of this data moved under a new category called Restaurants, and I needed to update the category attribute on the Restaurant entities.
---------->
When moving to the new version, I wanted all of this data moved under a new category called Restaurants, and I needed to update the category attribute on the Restaurant entities.
I put this code in my App delegate:
-(void)makeCategory{
NSError *error = nil;
NSFetchRequest *fetch = [[NSFetchRequest alloc] initWithEntityName:@"Category"];
NSUInteger numberOfcategories = [self.managedObjectContext countForFetchRequest:fetch
error:&error];
//if there are no existing categories, then create a new one called Restaurants
if( numberOfcategories == 0 ){
NSLog(@"Categories not found, creating Restaurant Category");
Category *c=[NSEntityDescription insertNewObjectForEntityForName:@"Category"
inManagedObjectContext:self.managedObjectContext];
c.name=@"Restaurants";
//if there are existing restaurants then set their category attribute to point to the new //Restaurant category
NSFetchRequest *fetch1 = [[NSFetchRequest alloc] initWithEntityName:@"Restaurants"];
if ([self.managedObjectContext countForFetchRequest:fetch1 error:&error] >0) {
//make the new restaurant category relation
NSArray *fetchedObjs= [self.managedObjectContext executeFetchRequest:fetch1
error:&error];
for (Restaurants *r in fetchedObjs) {
r.category=c;
}
}
}
}
I called this function from didFinishLaunchingWithOptions: method .
References:
https://the-nerd.be/2012/02/05/how_to_do_a_lightweight_core_data_migration/
https://www.objc.io/issues/4-core-data/core-data-migration/