Основные данные - легкие миграции и файлы с несколькими основными файлами данных (xcdatamodel) - программирование
Подтвердить что ты не робот

Основные данные - легкие миграции и файлы с несколькими основными файлами данных (xcdatamodel)

У меня проблема с легким переносом при переносе из хранилища, который определяется двумя отдельными файлами xcdatamodel.

В версии 1.0 моего приложения у меня были модели, выпущенные в модель аналитики, модель-A и все остальное в модели-B. При компиляции модели группируются вместе, и все происходит плавно.

При работе над новой версией 1.1 я обновил модель-B, добавив новую модель модели в модель-B и установив ее как активную.

Проблема возникает при обновлении с 1.0 до 1.1. Похоже, что Core Data проверяет хранилище моделей на диске (созданное по версии 1.0) и ищет модель, которая ее описывает, но не может найти модель SINGLE, которая определяет весь магазин (модель-A охватывает только аналитику, а покрытия модели-B все остальное), поэтому он выдает ошибку "Ошибка поиска для источника".

Кто-нибудь нашел решение для разделения моделей, но все же позволяет обновлять + облегченные миграции для работы без лишних хлопот по определению пользовательских миграций?

Вот фрагмент кода, используемый для загрузки моделей:

    NSArray *modelNames = [NSArray arrayWithObjects:@"model-A", @"model-B", nil];
    NSMutableArray *models = [NSMutableArray array];
    for (NSString *name in modelNames)
    {
        LogInfo(@"loading model %@", name);
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:name withExtension:@"momd"];
        NSManagedObjectModel *model = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] autorelease];
        [models addObject:model];
    }

    // combine all the separate models into one big one
    objectModel = [[NSManagedObjectModel modelByMergingModels:models] retain];

    NSURL *documentsDirectory = [NSURL fileURLWithPath:[SuperFileManager documentsDirectory] isDirectory:YES];
    NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"database.sqlite"];
    NSError *error = nil;

    coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel];
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                                  [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                                                  [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
                                                  nil];

    if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                   configuration:nil
                                             URL:storeURL
                                         options:options
                                           error:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
4b9b3361

Ответ 1

После посещения лаборатории WWDC 2012 и встречи с командой Core Data кажется, что вы вынуждены вводить всю свою модельную информацию в одну xcdatamodel. CoreData недостаточно интеллектуальна, чтобы проверять существующие магазины как комбинацию созданных ею магазинов и все еще на диске. Как отметил К. Роальд, вы можете обработать старые файлы xcdatamodel, но довольно грустно, что Core Data не справляется с этим более элегантно.

Ответ 2

Я тоже столкнулся с этой проблемой. Я потерял несколько часов, пытаясь понять, что WTF - очень расстраивает.

Я считаю, что самый простой способ решить эту проблему:

  • Выберите, какую модель вы держите - скажем, ModelB, - и создайте для нее новую версию на основе опубликованной версии. Я буду называть опубликованную версию ModelBv1 и новую версию ModelBv1_merge.

  • Откройте содержимое XML файлов для ModelAv1 и ModelBv1_merge в текстовом редакторе (т.е. ModelA.xcdatamodeld/ModelAv1.xcdatamodel/contents и ModelB.xcdatamodeld/ModelBv1_merge.xcdatamodel/contents) и объедините XML вручную. Схема очень проста - просто скопируйте элементы <entity> и объедините элемент <elements> (в файл содержимого _merge), и все готово.

  • Откройте файл содержимого для вашего нового ModelBv2 и снова объедините содержимое ModelA в него.

  • Удалите ModelA из файла проекта.

Проверьте Xcode, что ModelBv1_merge и ModelBv2 выглядят разумно и содержат все, что вы ожидаете (объединение старой модели A и модели B). Постройте, и вы должны сделать.

(Я думаю, что у этого есть предостережение "при условии, что оба файла содержимого были написаны одной и той же версией Xcode", но я думаю, что если у вас есть старый файл содержимого, должно быть достаточно просто сделать Xcode переписать его, сделав тривиальный где-то измените.)

Ответ 3

У меня есть сценарий, в котором получена моя модель приложения, объединяющая несколько моделей, и мне удалось создать автоматическую облегченную миграцию следующим образом:

NSError* error = nil;
NSURL *documentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"db.sqlite"];
NSString* storePath = [storeURL path];
NSLog(@"Store URL: %@", storeURL);
if( [[NSFileManager defaultManager] fileExistsAtPath:storePath] ){
    // Load store metadata (this will contain information about the versions of the models this store was created with)
    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeURL error:&error];
    if(storeMeta){
        // Get the current model, merging all the models in the main bundle (in their current version)
        NSManagedObjectModel* model=[NSManagedObjectModel mergedModelFromBundles:nil];
        // If the persistent store is not compatible with such a model (i.e. it was created with a model obtained merging old versions of "submodels"), migrate
        if(![model isConfiguration:nil compatibleWithStoreMetadata:storeMeta]){


            // Load the old model
            NSManagedObjectModel*oldModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:storeMeta];

            // Compute the mapping between old model and new model
            NSMappingModel* mapping = [NSMappingModel inferredMappingModelForSourceModel:oldModel destinationModel:model error:&error];
            if(mapping){
                // Backup old store
                NSURL* storeBackupURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:@"db.sqlite.%@.bck", [NSDate new]]];
                BOOL done = [[NSFileManager defaultManager] moveItemAtURL:storeURL toURL:storeBackupURL error:&error];
                if(done){
                    // Apply the mapping
                    NSMigrationManager* migrationManager = [[NSMigrationManager alloc] initWithSourceModel:oldModel destinationModel:model];
                    BOOL done = [migrationManager migrateStoreFromURL: storeBackupURL
                                                                 type: NSSQLiteStoreType
                                                              options: nil
                                                     withMappingModel: mapping
                                                     toDestinationURL: storeURL
                                                      destinationType: NSSQLiteStoreType
                                                   destinationOptions: nil
                                                                error: &error];
                    if(done){
                        NSLog(@"Store migration successful!!!");
                    }
                }
            }
        }
    }
}

if(error){
    NSLog(@"Migration error: %@", error);
}

Ответ 4

Лучший способ обновить модель Core Data - это добавить версию. Если вы этого не сделаете, вы погибнете в результате сбоев, сообщите об опасности и тому подобное.

Добавление новой версии на самом деле довольно просто. Вы выбираете файл datamodel и выбираете "Редактоp > Добавить модель версии". Это позволит вам добавить новую версию базы данных на основе предыдущей модели. Затем вам необходимо установить текущую дату-дату: http://cl.ly/2h1g301b0N143t0b1k2K

iOs будет автоматически переносить данные (по крайней мере, в моем случае), когда будет установлена ​​новая версия.

надеюсь, что это поможет.