2017-04-25 2 views
0

Ich verwende Core Data in Kombination mit dem Mogenerator, um ein ziemlich großes und stark verknüpftes Datenobjektdiagramm zu verwalten.CoreData + mogenerator - Wie kann verhindert werden, dass `setValue (forKey:)` im Zwischendatamodel auf die 'human'-Klasse für die Entität im letzten Datenmodell verweist?

Aufgrund einiger unglücklicher Design-Entscheidungen in der Vergangenheit (Speichern von Daten als Transformable in einem Objekt), stoße ich bei der Migration auf Speicherprobleme; Die Migration ist schwierig genug, so dass das Lightweight nicht ausreicht, und die benutzerdefinierte Migration versucht, alles im Speicher zu laden und kläglich zu versagen.

Basierend auf dem hervorragenden Core Data book von Marcus Zarra, habe ich seinen progressiven Migrationsansatz angepasst, um sukzessive Migrationsdurchläufe gemäß einer leichtgewichtigen, benutzerdefinierten oder eigenen Migrationsstrategie zu kombinieren. Ich verwende dies, um ein intermediäres Datenmodell zu erstellen, in dem ich mein "Big Data" -Objekt lade und es in eine externe Datei auf der Festplatte schreibe, und halte stattdessen die URL zu dieser Datei.

Grundsätzlich sieht das wie folgt aus:

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

Zwischen den zwei Leichtbau-Migrationen, I eine NSPersistentStoreController auf das Zwischenmodell anschließen, Objekte holen, die fetchLimit geändert werden müssen, um unter Verwendung fetchBatchSize; schreibe die Daten in eine Datei auf der Festplatte und annulliere die Daten, die im Objekt selbst gespeichert sind. Während dieser Zeit speichere ich regelmäßig den Moc und schreibe die verarbeiteten Objekte ab.

Das funktioniert ziemlich gut .. aber ... ein anderer Teil der Migration funktioniert nicht sehr gut, wo ich eine Beziehung entfernt und durch eine berechnete Eigenschaft in der 'Mensch' Klasse der generierten Datei ersetzt habe. , dh

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

nach dem gleichen Prinzip, in der 'v1.5-to-v1.5' passieren, ich bin die Informationen in myRel auf einer anderen Ebene gespeichert bewegt und versucht, die Beziehung zu nil zu setzen danach. Die App, die das Datamodell v2 verwendet, greift weiterhin auf die Objekte zu, auf die in myRel mit derselben Schnittstelle verwiesen wird, weil ich sie als eine berechnete Eigenschaft hinzugefügt habe, die die verschobenen Daten abruft.

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

Hier ist der Code, der diesen Schritt tut:

// 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") 
} 

Diese letzte Zeile führt zu einem Laufzeit Absturz, einen Stacktrace zeigt, die das „Objekt“ Datei mogenerator für das endgültige Modell-Version, nicht erzeugt führt in für dieses Zwischenmodell

#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 ... 

Natürlich stürzt dies, weil das Datenmodell, an das ich arbeite enthalten nicht die in meiner berechneten Eigenschaft bezeichneten Einheiten myRel (das ist nur vorhanden, auf Datenmodell v2)

Das überrascht mich, ich habe die NSFetchRequest vor allem mit <NSManagedObject> in der Hoffnung zu haben ‚in Scheiben geschnitten weg‘ die zugrunde liegende dynamische Logik der MyEntity Klasse konstruiert, aber es scheint, Core Data/Swift folgern der Laufzeittyp basierend auf dem Entitätsnamen/der Beschreibung. Gibt es eine Möglichkeit, dies zu umgehen?

Ich habe auch versucht mit setPrimitiveValue, aber das verursacht mein Moc, um Änderungen zu verpassen Ich mache die Änderungen, die ich an meinen Objekten mache nicht auf diese Weise gespeichert werden.

+0

All dies zu schreiben half, das Licht etwas zu sehen. Es ist mir gelungen, das Problem zu umgehen, indem ich 'myRel' im Zwischendatenmodell in' myRelOld' umbenenne und auf dieses in der Zwischentransformation zugreife. Da die Beziehung in der Migration zum Datenmodell v2 entfernt wird, ist dies nicht so wichtig. Dennoch, wenn jemand mir einen Zeiger darauf geben kann, warum Core Data versucht, das "aktuelle Datamodell" -Entity anstelle des Zwischenmodells zu verwenden; Beachten Sie, dass meine berechnete Eigenschaft im neuesten Modell nicht mit '@ dynamic' /' @ NSManaged' gekennzeichnet ist; oder zeigen Sie einfach ein neues Licht auf das, was ich tue, immer willkommen! – Stavr0s

Antwort

0

All dies zu schreiben half, das Licht etwas zu sehen. Ich habe es geschafft, das Problem zu umgehen, indem ich myRel im Zwischendatenmodell in myRelOld umbenannte und auf dieses in der Zwischentransformation zugreift. Da die Beziehung in der Migration zum Datenmodell v2 entfernt wird, ist dies nicht so wichtig.

Verwandte Themen