Mittwoch, 2. Mai 2012

DbContext Merge für detached Entitäten

Spätestens ab dem Zeitpunkt, wo man beim Entitiy Framework mit detached Entitäten in Berührung kommt, steigt die Komplexität von dem zunächst sehr simplen EF Code First Ansatz.

AttachUpdated für detached Entitäten

Die Lösung eines AttachUpdated für detached Entitäten auf dem DbContext habe ich euch bereits zur Verfügung gestellt. Damit dies allerdings reibungslos funktioniert, müssen alle Ids korrekt mit übertragen werden. Bei ganzen Objektbäumen heißt dies aber auch, dass für alle Kind-Elemente die Ids ebenfalls korrekt übertragen werden müssen.
Problematisch wird es allerdings in zwei Fällen:

  1. der Objektbaum enthält mehrere neue Entitäten: dies führt zu einer Duplicate Key Exception, da versucht wird, mehrere Entitäten mit derselben Id (Guid.Empty) dem Context hinzuzufügen
  2. in dem Objektbaum 1-n Relationen existieren und an dieser Stelle in den zugehörigen Listen Elemente hinzugefügt bzw. gelöscht werden

In beiden Fällen hilft uns leider der AttachUpdated-Ansatz nicht weiter, obwohl er eine performante Lösung ohne DB-Roundtrip darstellt.

Merge & MergeChildren für detached Entitäten

Möchten wir die oben geschilderten Probleme umgehen, fällt mir derzeit keine andere Lösung ein, als DB-Roundtrips in Kauf zu nehmen. Vor allem bei der Problematik von 1-n Relationen im Zusammenhang mit dem Löschen einzelner Child-Elemente, sehe ich keine andere Lösung, außer möchte keine SQLs von Hand schreiben - denn schließlich kann das Entity Framework nicht die IDs der zu löschenden Elemente kennen.

Die nun folgende Lösung bietet eine Möglichkeit detached Entitäten mit den in der Datenbank vorhandenen zu vereinen. Dies geschieht sowohl auf einzelner Entitätsebene, als auch bei ganzen Kinde-Relationen. Zunächst schauen wir uns einmal das Setup an:

Der nachfolgende Code führt einen DB-Roundtrip pro Entität bzw. Child-Relationen aus, um einen Abgleich zwischen den Original-Werten und den nun zu mergenden Werten aus den detached Entitäten zu ermöglichen:

Beispiel-Nutzung

Eine Nutzung mit unseren Beispiel-Entitäten bzw. Context sieht dann folgendermaßen aus:

Mit dem Parameter "deleteOrphanedChildren" ist es zusätzlich möglich, anzugeben, ob Kind-Elemente, welche in der detached Entität nicht mehr existieren aus der Datenbank gelöscht werden sollen.

Solltet ihr weitere Fragen oder eine elegantere Lösung kennen, lasst es mich wissen :)

Keine Kommentare:

Kommentar veröffentlichen