I was referring a wonderful tutorial Swift Core Data Tutorial for migrations in core data.
The tut stated that migrations in core data go hand in hand with multiple versions of data model.
I was experimenting on light-weight migrations and got to figure out the following points:
Scenario - I had a data model and I tried to add a some new attributes to an entity and I got an error as -
iOS Version - 9.1
Swift Version - 2.2
"The model used to open the store is incompatible with the one used to
create the storeā
I then tried to enable migration without creating any new version by adding the code -
let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: URLPersistentStore, options: options)
Then I tried altering the database similarly, i.e added an attribute to an entity and hurrah !!, it didn't result in a crash. Even I tried to access the particular entity as well as attribute but did it successfully.
What happened is migration without having multiple versions.
Question -
So Is migration possible without having multiple versions of data model?
Link to sample code - https://www.dropbox.com/s/mnb2dzxn56ghuet/CoreDataSwift-NSFetchedResultsController-master-2.zip?dl=0
Beginning with iOS 9, Core Data will copy the data model to the persistent store, and use that as the starting point if lightweight migration is necessary and requested. As a result, lightweight migration is possible even if the old model version is not available. This only works with SQLite persistent stores, and only for lightweight model migrations.
This was described in the What's New in Core Data session at WWDC 2015.
Related
I actually have a project with 6 core data models like V1 to V6,all are on app stores now when I am trying to update app from one of the older version (core data modelV3) to the current version it crashes (schema mismatch)
when investigated actually V3 model version is different between two project version from older V3 Model to current Model V3.
as in V3 version i added new entity and did not do LightWeight migration(forgot to do it), now is it any way I can allow users to upgrade this older app version with V3 model to the current app version like by solving this (Missing migration issue)
Please suggest any way to add a missing migration model if possible to provide smith upgradtion of the older app version to the current app version.
addPersistentStore should automatically perform necessary lightweight migration. Check if that code is reachable in all your application starting paths.
For that to happen, you need to supply correct set of options, as below:
do {
let options = [ NSInferMappingModelAutomaticallyOption : true,
NSMigratePersistentStoresAutomaticallyOption : true]
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType,
configurationName: nil,
at: persistentStoreURL,
options: options)
} catch {
fatalError("Problem loading Persistent Store")
}
Please also make sure your main xcdatamodel file points to latest version of your datamodel. Also note that following picture is taken after selecting your latest version xcdatamodel file (yourdatamodel 2.xcdatamodel), not the root xcdatamodel file (yourdatamodel.xcdatamodel).
A word of caution:
Reconsider: do you really need something beyond lightweight? In most situations, lightweight should resolve your problems.
You can get away with lightweight by adding more fields and stop using older fields in your code, thus making the task easier for Core Data. For rows relying on older fields, simply run some insert/update/delete operation if core data model version change is detected.
In order to check where lightweight fails, you can consider enabling following XCode argument:
-com.apple.CoreData.MigrationDebug 1
If lightweight isn't capable of fully migrating your model (such as you have renamed your entities, or data types have changed, which is very unrealistic and you should really reconsider your design if you are doing this), then you can consider this somewhat complex solution:
add persistent store with older model version and back up existing rows in some external file (non core data)
deleting the old persistent store and recreate it using addPersistentStore + newer model version
use newer persistent store to insert backed up data
If all else fails, then consider mapping model alternative. Refer to this article for more details.
I have a model Version. The entity passPhrase of Version needs to be migrated to New entity passPhrase in Home model.
But the Home model is introduced in new version of database. It was not present in old xcdatamodel. How can I migrate data from
Version.passPhrase to Home.passPhrase
And the golden rule of CoreData migration is - avoid custom migration at any cost. :)
So the way to do this to use lightweight migration to add your new entity, and then just use a one off migration script to move your data over.
You can remove the passPhrase property from your Version class definition but you need to leave it in the model for now so you can still access the old data. This can be cleaned up at some time in the future when you are confident all of your users have upgraded to the newer version, or just leave it there forever.
To access the existing value during your copy just use [version valueForKey:#"passPhrase"] and then once copied clear it out the same way [version setValue:nil forKey:#"passPhrase"]
In core data, Changing Entity / Model mapping does not comes under light weight migration. You have to handle it manually by subclassing NSMigrationManager and implementing custom NSEntityMigrationPolicy.
Apple provides little documentation on the subject.Please check the Custom Core data migration with detailed example. Hope this will help.
In our existing app, we have many different version of xcdatamodel:
+ TheApp.xcdatamodel
TheApp.1.0.xcdatamodel
TheApp.1.1.xcdatamodel
TheApp.2.0.xcdatamodel
...
We know that the traditional way of doing database migration testing is what have been proposed in this question: How to Test Core Data Migration With an App Already in the App Store? In short, it works like the following:
install a old version of the app;
create some data in the old version of the app;
install the new version on top it;
see if everything is migrated properly.
We have been using this migration testing method for all our previous version of the app. Our QAs will perform the above steps and then judge by themselves that whether migration is successful or not.
However, in the most recent upgrade, we have changed a lot in our data model. It doesn't sound like such a good idea to ask the QAs to remember what have been created in the old version of the app and know what have been missing or not during migration. Therefore, we would like to see whether it is possible to write unit testing for the database migration by the developers ourself.
So one of the first step is to generate test data. Notice that we can see all the previous version of the xcdatamodel from within our Xcode project, it seems that it is possible. In a nutshell, the question:
Is it possible to generate test data of previous version of xcdatamodel programmatically from within our current version of the app?
Please let me know what you think. Suggestions are also acceptable.
This is how we do it: we need to first get an URL to any model you would like to work with, and then create a managedObjectModel from it.
let oldModelUrl = NSBundle.mainBundle().URLForResource("CoreDataExample.momd/CoreDataExample",
withExtension: "mom")!
let oldManagedObjectModel = NSManagedObjectModel.init(contentsOfURL: oldModelUrl)
Referece: https://medium.com/#yzhong.cs/1d9f941b3168.
I am trying to sync the database (using core data) using CBLIncrementalStore. In managedObjectModel i am adding updateManagedObjectModel method. My data model has 7 versions, every time app is started i get crash on line entity.properties = properties;
But when there is only one version it is working fine. So does couch base not support the core data model versions ?
we are investigating this issue and will continue to add and comment on this question on our GitHub repo
I have an existing iPad application to which I've just added core data versioning. I've been through the documentation and followed the steps detailed. Now after choosing my new model as the current versioned model and trying to run it on my dev device from xCode I get the following error:
2012-03-28 07:35:42.137 DocsOnTap[2603:707] CoreData: error: (1) I/O error for database at /var/mobile/Applications/06EECF01-3598-4513-8A3A-BE4FD49EEBF6/Documents/.DocsOnTap.sqlite.migrationdestination_41b5a6b5c6e848c462a8480cd24caef3. SQLite error code:1, 'table Z_2TAG already exists'
The only change that I made to my model was to add in a single new entity. I have a table named Tag in my model - that appears to be what the error is referring to.
If I revert my current versioned model back to the previous model version then I can run my app on my dev device from Xcode without error.
I have read that there can be problems trying to use core data migration on dev devices. However I just want to test the process to be sure that when we update our app in the Appstore the migration works as expected for our customers.
In my case the same error appeared due to Renaming ID which was set in the Data Model inspector for the Entity. After I removed the Renaming ID the problem'd gone.
Well this was an obscure error. The entity that I was adding was named AppKeys - this must be the name of an entity used internally by core data or SQL Lite. I went back to scratch and found that I could add and migrate other attributes and entities without any problems. However if I tried once again to add my entity named AppKeys then I got the same error saying that 'table Z_2TAG already exists'. So the resolution to my problem is to choose another entity name. It is a pity that this is not documented somewhere obvious - or that the error was not more helpful. Anyway hopefully this might just help someone else one day.