Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data Versioning manually

I developed an app, iCollege, and now I want to make the app much better.
While the testing I wanted to restore the data from a backup. At launching iCollege the app crashes because it could not be versioned by Core Data. My question now is if it is possible to version a Core Data file manually, i.e. going through every Managed Object of the existing file and fit the objects to the active Model Version.

Is something like that possible?

EDIT: Thank you very much for your fast and detailed answer. I think that I explained my question not very good. Here is another description of my problem.
I have a file created with Core Data with a few Objects of the entities Course and Teacher. I replace the Core Data file of my app with this file. When the app launches the next time I want to call a method which reads the Managed Objects of the file with the objects of Course and Teacher and convert it into the Entities, e.g. Subject and Professor. The attributes may be changed, too. My question is if I can do this, i.e. can I version the Core Data file on my own?
I hope my question is now checkable. :-)

like image 892
Paul Warkentin Avatar asked Jun 20 '11 15:06

Paul Warkentin


2 Answers

While theoretically, you can migrate your data manually, it's probably not worth the effort. You want to use automatic lightweight migration.

To perform automatic lightweight migration, you need to have two data models set up, then in code, you tell Core Data to perform the migration. This means that you should not modify your data model until you finish reading this. If you have, (automatically or manually) restore your old model. You'll need it to do the migration. Here's how automatic lightweight migration works:

First, you need to add a model version to your data model. Select the existing model and then add a version from the Editor menu:

Select the model

Add a Model Version

You will be prompted to name your data model and choose which existing model to base it on.

enter image description here

Now, go ahead and make your changes to the new model. When you are done, you need to tell Core Data to use this new model as the current version. We're not up to the code yet, so this part is easy. (The code is easy too.) On the right hand side panel, choose the active model, as shown here:

enter image description here

Make sure that your model is selected in the left hand navigator, or else you might not see the options on the right. You should end up with something like this:

enter image description here

(I'm actually using version 2 here instead of version 3, but the idea is the same.)

Now, you need to make a quick change to your code so that Core Data knows to do the migration for you.

Inside of your persistentStoreCoordinator method in your app delegate, change this line:

if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]){

to the following (adding in the line preceding the if statement):

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


if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]){

You've essentially passed Core Data a dictionary of options which tells it to migrate the data store for you. (Take a close look at the preceding code, it will make sense after a couple of read throughs.)

Edit: You probably can do what you want. If I understand you correctly, you should create a new model version, perform lightweight migration, and them manually make the changes that you want. My above answer still stands, except that you will want to make some manual changes afterward.

like image 127
Moshe Avatar answered Sep 28 '22 05:09

Moshe


You can do this as follows. Core data allows you adding multiple persistent stores to a NSPersistentStoreCoordinator, so you need two stores associated to your coordinator. Note that it is not possible to use two different Managed Object Models (MOMs), you can only have one MOM for all of your stores.

While this may appear to be rather difficult, it is instead simple enough, given that Core Data also allows using configurations. A configuration has a name and an associated set of entities. The sets may overlap—that is, a given entity may appear in more than one configuration. See the associated documentation

You can now easily deal with your problem by having different entities in different stores, creating a model which will be a superset of all the entities you're going to deal with (or at least the union) and that defines the subsets you need as configurations. Then, for each individual store, you specify the associated configuration.

Something like (just an example snippet):

NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] init];
[coordinator addPersistentStoreWithType:type configuration:@"CourseAndTeacher" URL:aURL options:nil error:NULL];
[coordinator addPersistentStoreWithType:type configuration:@"SubjectAndProfessor" URL:anotherURL options:nil error:NULL];

NSManagedObjectContext *context = [[NSManageObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
like image 24
Massimo Cafaro Avatar answered Sep 28 '22 07:09

Massimo Cafaro