CoreData+mogenerator - Как предотвратить `setValue(forKey:)` в промежуточной модели данных для ссылки на класс "человек" для сущности в конечной модели данных?

Я использую Core Data в сочетании с mogenerator для управления довольно большим и сильно связанным графом объектов данных.

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

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

В основном это выглядит так:

     v1   ----(lightweight)---------->  v1.5   --(lightweight)-->   v2
                         |                             |
* myData: Transformable  |  * myData: Transformable?   | * myDataUrl: String
                         |  * myDataUrl: String        |

Между двумя легкими миграциями я подключаю NSPersistentStoreController в промежуточную модель, выберите объекты, которые необходимо изменить, используя fetchLimit, fetchBatchSize; записать данные в файл на диске и обнулить данные, хранящиеся в самом объекте, во время которого я регулярно сохраняю данные moc и выполняю ошибки обработанных объектов.

Это работает довольно хорошо... но... есть другая часть миграции, которая работает не очень хорошо, где я удалил отношение и заменил его вычисляемым свойством в классе "Human" в сгенерированном файле., Т.е.

     v1   ----(lightweight)---------->  v1.5   --(lightweight)-->   v2
                              |                             |
* myRel ->> [Some object]     | * myRel ->> [Some object]?  |  (nothing stored here)
                                                               computed property `myRel` in the `MyEntity` human class

По тем же принципам, на проходе 'v1.5-v1.5', я перемещаю информацию, хранящуюся в myRel на другой уровень и пытается установить отношения к nil после этого. Приложение, использующее модель данных v2, все еще получает доступ к объектам, указанным в myRel используя тот же интерфейс, потому что я добавил его как вычисляемое свойство, которое извлекает перемещенные данные.

public var myRel: [Some object] { return ... }

Вот код, который делает это движение:

// Note that since I'm not working on the current data model version in this
// so-called migration pass, I cannot/should not refer to the real `MyEntity` class that
// mogenerator generates for me. 
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "MyEntity")

let objects = try? moc.fetch(fetchRequest)
objects.forEach { object in
    // Process objects in `myRel` and move them to a different level
    let toProcess = ($0.value(forKey: "myRel") as? NSOrderedSet)?.array as? [NSManagedObject]?

    // ... process ...

    // Now nullify the original relationship
    $0.setValue(nil, forKey: "myRel")
}

Эта последняя строка вызывает сбой во время выполнения, показывая трассировку стека, которая приводит к генератору файлов "Объект", созданному для окончательной версии модели, а не для этой промежуточной модели

#0  0x0000000100f6885e in MyEntity.myRel.getter at ...
#1  0x0000000100f68732 in @objc MyEntity.myRel.getter ()
#2  0x000000010ebf7db7 in _PF_Handler_Public_GetProperty ()
#3  0x000000010124f221 in NSKeyValueWillChangeBySetting ()
#4  0x0000000101249798 in NSKeyValueWillChange ()
#5  0x000000010121f618 in -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:] ()
#6  0x0000000100f47222 in NSManagedObject.setValue<A where ...> (Any?, for : A) -> () at ...

Естественно, это происходит сбой, потому что модель данных, над которой я работаю, не содержит сущностей, указанных в моем вычисляемом свойстве myRel(они присутствуют только в datamodel v2)

Это удивляет меня, я построил NSFetchRequest особенно с <NSManagedObject> в надежде "отрезать" основную динамическую логику MyEntity класс, но, похоже, Core Data/Swift выводит тип среды выполнения на основе имени / описания объекта. Есть ли способ обойти это?

Я также пытался использовать setPrimitiveValue, но это приводит к тому, что мой moc пропускает изменения. Я делаю изменения, которые я делаю в своих объектах, таким образом не сохраняется.

1 ответ

Записывание всего этого помогло немного увидеть свет. Мне удалось обойти проблему, переименовав myRel в промежуточной модели данных для myRelOld и доступ к этому в промежуточном преобразовании. Поскольку связь при миграции к модели данных v2 удаляется, это не имеет большого значения.

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