NSRangeException после миграции основных данных

После добавления новой версии модели Core Data в мое приложение я выполнил облегченную миграцию, по-видимому, успешно. Перенесенный файл загружен нормально, но при первой попытке доступа к атрибуту через определенные отношения приложение вылетает с NSRangeException: '*** -[__NSArrayM objectAtIndex:]: index 4294967295 beyond bounds [0 .. 35]', Эти отношения работали хорошо до миграции. Я знаю из других постов здесь, что 4294967295 действительно -1, но единственное, что я могу идентифицировать с 36 элементами в моем приложении / данных, - это то, что в модели данных имеется всего 36 объектов (для справки: у извлекаемой связи в таблице 58 элементов).

Вопрос:

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

Провал:

Ошибка происходит со следующим кодом в "myobject":

[[self object2] text];

Отношение object2 является взаимно-однозначным, необязательным в обоих направлениях, и ни прямая, ни обратная связь не изменялись между моделями данных. text Атрибут, вероятно, не имеет значения, потому что, когда возникает ошибка, awakeFromFetch не достигается в object2. Если я назначу [self object2] переменная до вышеприведенного утверждения, назначение успешно и сообщает data: <fault>,

База данных:

Глядя на базу данных в sqlite3, я замечаю следующее:

  1. Значения индекса для прямых и обратных связей кажутся правильными в каждой таблице.
  2. Таблица object2 имеет два столбца для обратной связи вместо столбца до миграции (ZMYOBJECT как и раньше и дополнительный Z2_MYOBJECT, который является пустым для всех строк). Никакие другие отношения не были добавлены, чтобы объяснить этот столбец.
  3. в Z_PRIMARYKEY таблица, все записи после миграции показывают -1 за Z_MAXтогда как до миграции они показывали ноль для пустых таблиц и максимальное количество строк для заполненных таблиц. Обновление вручную Z_MAX чтобы правильные значения не помогли с исключением. Все Z_SUPER значения были правильными.

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

Общие изменения схемы:

В исходной версии модели данных было четырнадцать объектов, из которых только четыре были заполнены данными (приложение все еще находится в разработке). Семь были субъектами высшего уровня, а семь - дочерними объектами трех субъектов высшего уровня.

В целевой версии модели данных было добавлено 22 объекта, некоторые из которых были верхнего уровня, а также некоторые дочерние объекты с десятками взаимосвязей, включая некоторые, добавленные к существующим объектам.

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

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

Выводы:

Это неверное предположение, но если подсчет 36 объектов не является совпадением, кажется, что когда "myobject" пытается выполнить ошибку в "object2", он не имеет допустимой ссылки на таблицу и пытается загрузить таблицу номер -1., вызывая исключение. Дело в том, что простое назначение [self object2] успешно, однако, не вяжется с этим выводом.

Есть идеи?

3 ответа

Решение

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

Эта проблема:

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

Решение:

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

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

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

Ваши сообщения были полезны, когда я столкнулся с этой проблемой. Спасибо. [Вы уже сообщили об ошибке?]

Вот еще несколько экспериментальных результатов, но, увы, не очень удачное решение.

  • Моя схема изменила аналогичным образом добавленный подтип объекта, который не имеет дополнительных атрибутов или связей. Сообщение об ошибке совпадает с вашим, за исключением [0 .. 19], Это соответствует 20 типам сущностей, подтверждая вашу гипотезу. Как и в вашей ситуации, ошибка произошла при попытке получить доступ к свойству объекта после завершения миграции.

  • Добавление фиктивного атрибута и фиктивной самосвязи с новым типом сущности не избежало сбоя после миграции. (Однако я не тестировал этот новый тип сущности как единственное изменение схемы, так как ранее я выдвинул это изменение схемы в альфа-тестеры.)

  • Я наблюдаю Z2_MYOBJECT столбец и Z_PRIMARYKEY.Z_MAX = -1 симптомы после успешных миграций для других изменений схемы, поэтому они могут не быть проблематичными вообще. Значения -1 лениво заменяются соответствующими максимальными значениями. Дополнительный столбец может использоваться во время миграции.

  • В моем случае супертип новой сущности имеет упорядоченное отношение ко многим. В очень простом случае, когда все хранилище данных содержит только один экземпляр объекта (экземпляр этого типа сущности без исходящих связей отношений), миграция схемы завершается успешно. Это имеет дополнительный Z2_MYOBJECT столбец и Z_PRIMARYKEY.Z_MAX = -1 значения и, тем не менее, результирующее хранилище данных работает нормально при добавлении объектов оттуда.

  • Я пытался создать модель отображения, но безуспешно, чтобы Core Data применил ее. Отключение выведенного на карту сопоставления просто сделало невозможным перенос основных данных. Есть ли хитрость? Нужно ли писать собственный код миграции для вызова модели отображения? Это Xcode 4.6.2, так что старая ошибка давно исчезла.

  • При использовании git для прокрутки модели кода и данных назад или вперед для проведения эксперимента кажется необходимым (1) закрыть и снова открыть проект Xcode и (2) выполнить чистую сборку. В противном случае Xcode может аварийно завершить работу и / или выйти из состояния смешения.

  • Чтобы экспериментально откатиться назад, необходимо удалить .momd/ каталог или все приложение с целевого симулятора / устройства iOS (или разверните приложение через iTunes или TestFlight), поскольку повторное развертывание через XCode не удалит устаревшие файлы (например, .mom а также .omo определения модели данных), что, в свою очередь, позволяет приложению выполнять легкие миграции, чего не может сделать само развернутое приложение.

  • Что касается сопоставления сущностей для использования для добавленного типа сущностей, обратите внимание, что когда базовые данные применяют модель сопоставления, они копируют сущности из старого хранилища данных в новое. Это не изменение таблиц на месте. Вы не хотите, чтобы он "пропускал" свойства (включая унаследованные свойства), если вы не хотите их отбрасывать.

  • Однако, поскольку изменение схемы добавило тип сущности, у этой сущности нет экземпляров для переноса, поэтому правила пользовательской модели сопоставления не имеют значения.

Таким образом, мне интересно, если что-то еще привело к остановке ваших сбоев, например, экспериментальный .mom файлы или пользовательский код миграции. Ваш обходной путь выдержал?

После 2 дней экспериментов я решил, что на этот раз моим альфа-тестерам придется жить без переноса данных. К счастью, это произошло без производственных клиентов. Но это не дает мне уверенности в базовых данных.

У меня был такой же NSRangeException после добавления базовой версии модели данных при доступе к любому экземпляру конкретного объекта после автоматической упрощенной миграции. В моем случае диапазон также соответствовал количеству объектов в моей модели.

Я сгенерировал модель сопоставления с Xcode 4.6 (4H127), используя File > New > File... а затем выбрав Core Data > Mapping Model, Это привело к крушению (d), превратившемуся в -[NSSymbolicExpression length]: unrecognized selector sent to instance...

Решение

Проблема в моем случае заключалась в том, что у моей сущности, вызвавшей первоначальный сбой, были отношения size, которое является зарезервированным словом, перечисленным в Руководстве по программированию предиката Apple. Изучение модели отображения показало, что зарезервированное слово было написано с большой буквы в выражении значения для отношения:

FUNCTION($manager, "destinationInstancesForEntityMappingNamed:sourceInstances:" , "PNSizeOptionToPNSizeOption", $source.SIZE)

Я нашел решение в Руководстве по программированию версий базовой модели данных и миграции данных:

Зарезервированные слова в выражениях пользовательских значений: если вы используете выражение пользовательских значений, вы должны экранировать зарезервированные слова, такие как SIZE, FIRST и LAST, используя # (например, $source.# Size).

К сожалению, алгоритм Xcode для генерации модели отображения не распознал зарезервированное слово, и мне пришлось изменить путь ключа выражения в инспекторе отображения отношений на $source.#size, Это решило проблему. Я предполагаю, что предполагаемая модель отображения основных данных столкнулась с аналогичной проблемой во время упрощенной миграции.

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

Другие вопросы по тегам