我將核心數據與mogenerator結合使用來管理一個相當龐大且嚴重鏈接的數據對象圖。由於過去有些不幸的設計決定(將數據存儲爲對象中的Transformable
),我在執行遷移時遇到了內存問題;遷移非常困難,以至於輕量級技術無法覆蓋它,並且自定義遷移嘗試將所有內容加載到內存中並導致失敗。CoreData + mogenerator - 如何防止中間數據模型中的setValue(forKey:)引用最終數據模型中的實體的'人類'類?
基於Marcus Zarra出色的Core Data book,我已經調整了他的漸進式遷移方法,能夠根據輕量級,自定義或「編寫自己的」遷移策略混合並匹配連續的遷移過程。我使用它來創建一箇中間數據模型,在該數據模型中加載我的「大數據」對象並將其寫入磁盤上的外部文件,然後將url保存到該文件中。
基本上,這看起來像這樣:
v1 ----(lightweight)----------> v1.5 --(lightweight)--> v2
| |
* myData: Transformable | * myData: Transformable? | * myDataUrl: String
| * myDataUrl: String |
在兩間輕質遷移之間,我掛鉤一個NSPersistentStoreController
至中間模式,取這需要使用fetchLimit
,fetchBatchSize
被改變的對象;將數據寫入磁盤上的文件,並使存儲在對象本身中的數據無效,在此期間,我定期保存moc並對處理對象進行故障排除。
這很好用..但是......還有另一部分遷移工作不太好,我已經刪除了一個關係,並用mogenerated文件的'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")
}
最後一行導致運行時崩潰,顯示出通向的最終模型版本生成的「對象」文件mogenerator堆棧跟蹤,不這個中間模型
#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 ...
當然,這是因爲崩潰上我的工作不包含在我的計算財產中提到的實體數據模型(那些只是存在於數據模型V2)
此驚喜,我在具有「切片遠」的MyEntity
類的底層的動態邏輯的希望構造的NSFetchRequest
特別是與<NSManagedObject>
,但似乎核心數據/夫特推斷基於實體名稱/描述的運行時類型。有什麼辦法可以繞過這個嗎?
我也嘗試過使用setPrimitiveValue
,但這會導致我的moc錯過更改。我使我對對象所做的更改沒有以這種方式保存。
寫下這一切有助於看到光線。 我設法解決了這個問題,將中間數據模型中的'myRel'重命名爲'myRelOld',並在中間變換中訪問那個。由於在遷移到數據模型v2時刪除了這種關係,所以這並不重要。 不過,如果任何人都可以給我一個指示,說明爲什麼Core Data試圖使用'當前數據模型'實體而不是中間數據;請注意,我在最新模型中的計算屬性未標記爲「@ dynamic' /'@ NSManaged';或者只是展示我正在做的事情的新亮點,隨時歡迎! – Stavr0s