Миграция моделей данных Core Data

Core Data позволяет модифицировать модель данных и продолжать использовать её с существующим кодом.

После сложных изменений надо делать mapping модель, которая проводит соответствие между старыми полями и новыми.

Core Data использует встроенное версионирование. Core Data может идентифицировать версию модели данных в приложении и версию persistent store, который открывается. Если они не соответствуют друг другу, то вы получите ошибку.



Механизм версионирования основывается на концепции пакетов Mac OS - то что кажется файлом на самом деле папка. Различные версии модели данных хранятся в одном пакете. Для того чтобы добавить новую версию надо выбрать Editor - Add Model Version.... Для того чтобы переключиться на конкретную версию надо сделать выбор в секции  Versioned Core Data Model:


На рисунке ниже в секции versioning есть hash modifier и вы можете использовать его для перезаписи default hashing behavior для сущности или атрибута. На основе этого Core Data сравнивает совместимость двух моделей.


Вы также можете переименовывать сущности и атрибуты используя  renaming ID приведенный в той же секции. В это поле надо записывать предыдущее значение имени. При запуске lightweight migration преобразование сделает сама Core Data.

Если вы сделали изменения модели данных, которые могут быть обработаны с помощью автоматической lightweight-миграции, то надо включить её указав опцию для addPersistentStoreWithType. По умолчанию параметр в options передается nil:

/**
Returns the persistent store coordinator for the application.
If the coordinator doesn’t already exist, it is created and the
application’s store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory]
URLByAppendingPathComponent:@”Estimator.sqlite];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator
addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
URL:storeURL options:nil error:&error])
{
....code continues....

Нужно создать конфигурацию для lightweight-миграции:


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]) {
// Handle the error.

Также можно протестировать автоматическую миграцию используя метод класса NSMappingModel:


+ (NSMappingModel *)inferredMappingModelForSourceModel:
(NSManagedObjectModel *)source
destinationModel:(NSManagedObjectModel *)destination
error:(NSError **)error

Базовая mapping-модель слегка сложнее автоматической lightweight-миграции. Основная разница в том, что вы показываете соответствие между старыми и новыми полями. Перед началом вам нужна исходная модель и конечная модель. Это могут быть версии одной и той же модели данных или это могут быть отдельные модели данных. Создание mapping-модели делается через главное меню:

Настройка маппинга сущностей:

Изменение маппинга атрибутов: