Freitag, 4. Mai 2012

EF Entitäten: Finden der Primary Keys

Es gibt verschiedenste Gründe, dass man die Werte der Primary Keys (PKs) von Entitäten im Entity Framework haben muss.
Ein Beispiel ist hierbei sicherlich die Find-Methode auf dem DbSet, welche ein object-Array entgegennimmt, um eine beliebige Anzahl von PKs zu unterstützen und das gesuchte/eindeutige Objekt zurückzugeben.

Um die PKs herauszubekommen, gibt es verschiedene Ansätze.

1. Lösung mithilfe des KeyAttribute

Die einfachste Lösung basiert darauf, dass die PKs in den Entitätsklassen mit dem "KeyAttribute" versehen sind. Falls man Guids als PKs verwendet, könnte eine Lösung folgendermaßen aussehen:

Allerdings gibt es mit dieser Lösung verschiedene Probleme:

  • Bisher wird nur ein PK unterstützt, allerdings kommt es oft vor, dass der Primary Key sich aus mehreren Schlüsseln zusammensetzt
  • Bisher werden nur Guids als Typen für den PK unterstützt
  • und meiner Meinung nach am Wichtigsten: diese Lösung setzt voraus, dass der PK mit dem KeyAttribute deklariert ist. Dies allerdings wird oft nicht gemacht, weil es schlichtweg nicht nötig ist, da EF mithilfe von Konventionen in der Lage ist, dies selber herauszufinden

2. Lösung (und bessere) mithilfe des Metadata Workspace

Eine durchaus bessere Lösung hat heute Arthur, Mitglied im EF Team bei Microsoft, in seinem Blog vorgestellt. Er versucht in seinem Artikel The key to AddOrUpdate Lösungen für eine generische AddOrUpdate-Methode aufzuzeigen.

Im Abschnitt "Finding primary key property names" befindet sich aus meiner Sicht allerdings der interessanteste Part des Artikel, nämlich, wie man mithilfe des internen Metadata Workspaces die PKs bekommen kann.

Allerdings habe ich mit seinem Code-Snippet direkt ein Problem gehabt, da es nicht bei Proxy Typen funktioniert, welche EF erzeugt. Außerdem verhindert er nicht die Lazy-Execution, was ich für einen Performance-Schwachpunkt halte. Ich habe sein Snippet dementsprechend geändert und noch um Überladungen ergänzt:

Kommentare:

  1. IMHO solltest du der Vollständigkeit halber den (trivialen) Code für IsDefaultValue() angeben, sonst compiliert dies hier:

    return context.GetKeyValuesFor(entity).All(_ => _.IsDefaultValue())

    nicht.

    AntwortenLöschen
  2. Mein Versehen - bitteschön:

    public static bool IsDefaultValue(this object value)
    {
    return value == null
    || (value.GetType().IsValueType
    && Equals(Activator.CreateInstance(value.GetType()), value));
    }

    AntwortenLöschen