https://www.jsecomputing.com/data-migration-service-provider/

Core Data Heavyweight Migration

Wilson Shakya

--

We all know what core data is and how powerful it is to manage the local database.

But as the project starts growing, the attributes of entities or sometimes the entire schema of entities might change.

To deal with such changes, core data provides another powerful feature named “Core Data versioning and migration”

So What is Core Data versioning and migration?

Core data allows you to migrate data from one version of the data model to another.

There are two types of migrations you can perform. Lightweight and Heavyweight.

Lightweight Migration

If changes in the new schema are not very complex then you can simply use lightweight migration.

To perform lightweight migration, all you have to do is, set property ‘shouldMigrateStoreAutomatically’ and ‘shouldInferMappingModelAutomatically’ true.

As the name suggests, core data will automatically infer the mapping model and perform the data migration.

You can use lightweight migration, when

  1. New entity/attribute/relationship is added
  2. Any entity/attribute/relationship is removed
  3. The name or type of any entity/attribute/relationship is changed

Heavyweight Migration

Now let’s come to the topic of the blog.
What is heavyweight migration and when do we perform it?
So first of all what does apple say about heavyweight migration?

“Use heavyweight (manual) migration in rare cases when changes to the data model exceed the capabilities of lightweight migration.”

Well, that’s all they say about it.

We perform heavyweight migration when we have either normalized or generalized our database.
In such cases, lightweight migration won’t help us. We will have to manually map attributes of the old data model to the new data model, and doing so is called heavyweight migration.
Other use cases of heavyweight migration could be when you want to perform some serious customization on data.

You can find sample project Here

So what happened is, I have an app that is used by Swedish(people of Sweden) and by the Finns(people of Finland).

Initially, when I designed the data model architecture, I just kept one entity with the name “InternationalUser” which I used to contain data of all users.

But now due to project requirements, I need to have two different entities. One for Sweden and one for Finland and have to replace one city from both( Sweden and Finland) with another city.

So let’s see how it’s done.

Step 1

Let’s start with creating a new project. Make sure “Use Core Data” is checked

Step 2

Let’s design the schema of the first version of the data model, which will be later replaced by the new version.

Step 3

In the third step

  • I inserted some dummy data in the entity “InternationalUser”.
  • Created table view and populated with dummy data.

So our app looks something like this.

The text in grey is the user’s name and the text in black is their city.

Step 4

To migrate from one version to a new version, WE NEED A NEW VERSION.

So let’s create one.

To create a new model version, You first open the existing data model window, then go to “Editor” and then click on “Add Model Version”.

So you will see a window something like this.
The first field is for the name of the new model version.

Step 5

Now let’s design a new schema. As I said earlier, now I want two different entities for Sweden and Finland users.

So I will create, two entities with the name FinlandUser and SwedenUser.

These two entities have the almost same attribute as the earlier “InternationalUser” entity except one “user country”. We are removing “user country” from our new data model version.

So our FinlandUser and SwedenUser entities will look something like this.

Step 6

This is probably the only step, which requires some coding. finally.

So let’s create a Swift class with the name SwedenUserMapping.

This class will be inheriting NSEntityMigrationPolicy.

NSEntityMigrationPolicy is the class, which allows us to take full control over the migration process. We can do n number of things using this class, like writing custom migration logic, mapping 1 attribute with N number of attributes and vice versa, running complex logic on data, etc.

PS: I could have used a single class to perform mapping and migration of both the entities, but for better clarity, I created two separated NSEntityMigrationPolicy classes, one for Sweden users and one for Finland users.

The only method we need to override is the createDestinationInstances.

So our SwedenUserMapping class looks something like this:

As per the apple document, createDestinationInstances(forSource:in:manager:) creates the destination instance(s) for a given source instance.

here source refers to the source entity(old data model), mapping refers to entity mapping and manager is the instance of NSMigrationManager.

NSMigrationManager performs the data migration using given mapping.

So What I am doing in my custom logic is,

  • Checking if sIntance.Entity is InternationalUser or not. If yes move ahead.
  • Storing attribute value into local variables
  • If user’s country is Sweden, then create an object of NSEntityDescription Class for entity SwedenUser into destination context(new data model).
  • Set all the values.
  • As I mentioned earlier, I need to replace one city from both (Sweden and Finland) with a new city. So in our SwedenUserMapping class, I am replacing city Trosa with Nora.

I wrote smilier logic in our FinlandUserMapping class.

Remember the createDestinationInstances method will only be called once to perform data migration. If data migration is completed successfully, It will never be called again.

Now we are done with the coding as well.

Step 7

The core and most important element of the data migration process is the Mapping Model.
We need to have a mapping model, Which will do mapping of attributes of the older version to attributes of the new version.
To create a mapping model, press command + N -> Scroll down to Core Data section -> Click on Mapping Model

The next window you will see is

Select the source of Mapping, which is your older version of the data model.

Clicking on next will navigate you to the below window.

Now select the target of your mapping model. Your target will be the new version of the data model.

Step 8

So you must be seeing something like this.

Two Entity Mapping with the same name as your entity’s name in the new version data model.

On your right-hand side, there will be Entity Mapping Inspector.

Currently, the source field has the value “Invalid Value”.

Clicking on it, We see all entities of the old data model version.

You select the entity of the old data model, which you want to map.

As soon as you select the source entity, core data will automatically map all fields and It will even change the entity mapping name.

Have another look at Entity Mapping Inspector and you will find one field with the name “Custom Policy”.

This field is to tell core data that “Do we have our mapping policy?”

Yes, We have. The one we just created, the “SwedenUserMapping”.

So just write its name in the Custom Policy field.

Do not forget to add the project module name with ‘.’, as a prefix.

Do the same with the Finland Entity Mapping as well.
The next thing we need to do is, double click on any of the model versions and you will see an inspector window on your right.

Here you will see an option with the name Model Version. Just select your new data model version. In our case it’s HeavyweightMigrationV2.

Step 9

Now open your app delegate file and look for lazy property persistentContainer and override its body with below peace of code.

We are setting shouldInferMappingModelAutomatically to true, which means, we want core data to infer mapping automatically.

So now we are all done with the heavyweight migration thing. let’s run the app and perform data migration.

Step 10

Just to confirm that our migration has been completed successfully, Let’s create two methods to load data from entities “SwedenUser” and “FinlandUser” respectively.

Now populate fetched data into our existing table view (The same, which we used to show InternationalUser data.)

Data of SwedenUser Entity
Data of FinlandUser Entity

So That’s all, We have successfully performed Heavyweight Migration. Cheersss…

Happy Coding

--

--