Проблема миграции основных данных: "ошибка миграции постоянного хранилища, отсутствует модель управляемого объекта источника."

Фон

  • Основные Данные Не Документа Какао проект с двумя управляемыми объектами Модели.
  • модель 1 остается неизменным. Модель 2 изменился, поэтому я хочу мигрировать магазин.
  • Я создал новую версию по дизайну > модель данных > добавить модель Версии в Xcode.
  • разница между версиями-это одно отношение, которое было изменено с одного на много.
  • Я изменения в модели, после этого сохранить.
  • Я сделал новую модель отображения, которая имеет старую модель как источник и новую модель как назначение.
  • Я обеспечена все картографические модели и модели данных и компилируются, и все скопировать в папку Мои пакет приложений.
  • я включил миграцию передача в словаре с NSMigratePersistentStoresAutomaticallyOption ключ как [NSNumber numberWithBool:YES] при добавлении Постоянный Магазин.
  • вместо слияния все модели в комплекте, я указал два модели, которые я хочу использовать (модель 1 и новая версия модели 2) и слился их использование modelByMergingModels:

Проблема

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

" ошибка миграции постоянного хранилища, отсутствует исходная управляемая объектная модель."

что я пробовал

  • я убираю после каждой сборки.
  • Я пробовал различные комбинации из имея только модель я миграция в ресурсы, компилируемые, или оба.
  • С момента сообщения об ошибке подразумевается, что он не может найти источник модель для моей миграции, я пробовал каждая версия модели в как папка Resources, так и составленный.
  • я убедился, что я не сделать действительно основную ошибку возврат к оригиналу версия моей модели данных. Приложение работает нормально.
  • Я удалил отображение Модель и новая версия этот модель, очищенная, затем воссозданная.
  • Я пробовал сделать другое изменение в новой модели - удаление объекта вместо.

Я в тупике.

Я не могу помочь, но думаю, что я совершила огромную ошибку где-то, что я не вижу. Есть идеи?

4 ответов


два варианта:

  1. ваша исходная модель в вашем приложении не соответствует фактическому хранилищу на диске.
  2. ваша модель отображения не соответствует вашей исходной модели.

поворот на отладка основных данных и вы должны иметь возможность видеть хэши, которые ищут основные данные, когда они выполняют миграцию. Сравните эти хэши с тем, что находится в вашем магазине на диске, и посмотрите, совпадают ли они. Аналогично, отладка должна позволить вам увидеть хэши в модели сопоставления, чтобы помочь вам сопоставить все.

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

обновление 1

место для изменение исходной и целевой моделей переместилось в нижнюю часть окна редактора:


вместо объединения всех моделей в bundle, я указал две модели Я хочу использовать (модель 1 и новый версия модели 2) и объединили их использование modelByMergingModels:

это не кажется правильным. Зачем объединять модели? Вы хотите использовать модель 2 перенос вашего магазина от модель 1.

из ссылки на класс NSManagedObjectModel

modelByMergingModels:

создает единый модель из массива существующих модели.

вам не нужно делать ничего особенного / конкретного с вашей исходной моделью (модель 1).. пока он находится в вашем комплекте, автоматический легкий процесс миграции обнаружит и использует его.

Я бы предложил отказаться от модели отображения, которую вы создали в XCode, так как я видел ужасные показатели по сравнению с автоматическим-легкий миграции. Ваш пробег может отличаться, мои изменения между моделями отличаются от ваших, но я не удивлюсь. Попробуйте выбрать время с вашей собственной моделью отображения в комплекте и без нее.

 /* Inferred mapping */
 NSError *error;
 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                          [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,nil];
 NSPersistentStore *migratedStore = [persistentStoreCoordinator addPersistentStoreWithType:nil
                                                                             configuration:nil
                                                                                       URL:self.storeURL
                                                                                   options:options
                                                                                     error:&error];
 migrationWasSuccessful = (migratedStore != nil);

вы можете проверить в своем коде, что ваша исходная модель доступна, пытаясь загрузить ее и убедиться, что она не равна нулю:

NSString *modelDirectoryPath = [[NSBundle mainBundle] pathForResource:@"YourModelName" ofType:@"momd"];
if (modelDirectoryPath == nil) return nil;
NSString *modelPath = [modelDirectoryPath stringByAppendingPathComponent:@"YourModelName"];
NSURL *modelFileURL = [NSURL fileURLWithPath:modelPath];
NSManagedObjectModel *modelOne = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelFileURL];
if (modelOne == nil) {
    NSLog(@"Woops, XCode lost my source model");
}
else {
    [modelOne release];
}

это предполагает, что в вашем проекте у вас есть ресурс"YourModelName.xcdatamodeld" и "YourModelName.xcdatamodel все" в ее рамках.


кроме того, вы можете проверить, совместима ли эта модель с вашим существующим постоянным хранилищем перед миграцией:

NSError *error;
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:self.storeURL error:&error];
if (storeMeta == nil) {
    // Unable to read store meta
    return NO;
}
BOOL isCompatible = [modelOne isConfiguration:nil compatibleWithStoreMetadata:storeMeta];

этот код предполагает, что у вас есть метод -storeURL чтобы указать, откуда загружается постоянное хранилище.


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

Я написал этот метод (ниже) во время устранения этой проблемы. Это может быть полезно для тех, кто столкнулся с этим тип вопроса.

- (BOOL) checkModelCompatibilityOfStoreWithURL: (NSURL *) myStoreURL
                                 forModelNamed: (NSString *) myModelName
                                  withBasePath: (NSString *) myBasePath;
{
    NSError * error = nil;
    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:myStoreURL error:&error];
    if (!storeMeta) {
        NSLog(@"Unable to load store metadata from URL: %@; Error = %@", myStoreURL, error);
        return NO;
    }

    NSString * modelPath = [myBasePath stringByAppendingPathComponent: myModelName];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath: modelPath]) {
        // uh oh
        NSLog(@"Can't find model.");
        return NO;
    }

    NSURL * modelURL = [NSURL fileURLWithPath: modelPath];
    NSManagedObjectModel * model = [[[NSManagedObjectModel alloc] initWithContentsOfURL: modelURL] autorelease];
    BOOL result = [model isConfiguration: nil compatibleWithStoreMetadata: storeMeta];

    NSLog(@"Tested model, %@, is%@ compatible with Database", modelPath, result ? @"" : @" ~not~");

    return result;
}

этот фрагмент кода будет хранить метаданные.

NSError *error = nil;
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeUrl error:&error];
NSLog(@"%@", [storeMeta objectForKey: @"NSStoreModelVersionHashes"]);

В VersionInfo.plist (хранится в пакете скомпилированного приложения) содержит хэши, связанные с различными объектами в ваших моделях (кодировка base64). Аналогично, столбец BLOB в хранилище данных (Z_METADATA.Z_PLIST) содержит список свойств в двоичной кодировке с хэшами (также закодированными в base64) для каждой сущности, связанной с данными.

в - entitiesByName метод на NSManagedObjectModel полезен для сброса сущностей и хэшей, которые существуют в определенной модели.


у меня была похожая проблема. Я использовал +modelByMergeingModels:, но я не использовал модель отображения. Однако объединение моделей не работает с упрощенной миграцией данных.

из документов Apple:

для выполнения автоматической легкой миграции, основные данные должны быть в состоянии найти источник и назначения управляемого объекта модельs сам во время.

если вы используете +modelByMergeingModels: чем это используется для модель назначения. Однако основные данные не смогут найти исходную модель. Модель была создана с использованием +modelByMergeingModels: в старой версии приложения и основных данных пытается объединить модели, чтобы узнать исходную модель.

то, что я закончил, это то, что я (вручную) создал новый объединенный .xcdatamodeld путем редактирования XML-файлов моделей, добавил его в проект, удалил отдельный .xcdatamodelds из источников компиляции и вместо использования +modelByMergeingModels: использовать NSManagedObjectModel ' s -initWithContentsOfURL: с URL-адресом новой объединенной модели. Вероятно, я создам сценарий, который автоматически объединит модели в будущем.