Laden...

EF Core: Referenz auf Basis-Entity bei komplexen Ableitungen ohne TPT

Erstellt von Palladin007 vor 5 Jahren Letzter Beitrag vor 5 Jahren 889 Views
Palladin007 Themenstarter:in
2.080 Beiträge seit 2012
vor 5 Jahren
EF Core: Referenz auf Basis-Entity bei komplexen Ableitungen ohne TPT

Guten Nachmittag,

folgende Situation:

Ich hab ein Objekt, das pro Prozess einige Daten enthält. Daneben habe ich ein weiteres Objekt, das als Vorlage für so ein Prozess dient. Beide Objekte haben einige Gemeinsamkeiten, aber auch einige Unterschiede, sodass sich Vererbung anbietet.
Daneben sollen beide Objekte, sowohl der eigentliche Prozess, als auch die Vorlage dazu, eine Liste von zusätzlichen Daten haben, hier brauche ich eine m:n-Beziehung.

Ich hoffe, es wird klar, was ich vor habe 😃

Meine Frage ist nun: Wie setzt man das am besten auf einer relationalen Datenbank um?
Ich arbeite mit EF Core und einer SQL-Server-Datenbank auf.

Mir fallen dazu vier Optionen ein:

Option 1:
Für Prozess und Vorlage eine entsprechende Basis und das wird mit TPT gemappt. Das Problem ist allerdings, dass ich eine m:n-Beziehung für eine weitere Tabelle brauche und in dieser Verbindungs-Tabelle dann nicht klar ist, für welche Ziel-Tabelle der Fremdschlüssel sein soll.
TPH finde ich unpassend (oder unschön), da die Daten-Unterschiede recht umfangreich sein werden, einen konkreten technischen Grund dagegen habe ich aber nicht.
Gibt es eine halbwegs performante Möglichkeit, den Fremdschlüssel anhand einer Discriminator-Spalte in der m:n-Verbindungs-Tabelle auf eine andere Ziel-Tabelle "umzulenken"?

Ich versuche es Mal zu skizzieren, die NVARCHAR(MAX)-Spalten sind stellvertretend für viele weitere Spalten:

Process
BIGINT Id
NVARCHAR(MAX) Data
NVARCHAR(MAX) ProcessData

Template
BIGINT Id
NVARCHAR(MAX) Data
NVARCHAR(MAX) TemplateData

ListItem
BIGINT M_Id :::

Option 2:
Die Option 1, bloß mit TPH und dann damit leben, dass immer ein Großteil der Tabelle überflüssig ist.

ProcessOrTemplate
BIGINT Id
NVARCHAR(MAX) Data
NVARCHAR(MAX) ProcessData
NVARCHAR(MAX) TemplateData
BIT IsTemplate :::

ListItem
BIGINT M_Id :::

Option 3:
Ebenfalls nach TPH-Prinzip, allerdings die Unterschiede in eigene Tabellen auslagern und pro Ableitung eine entsprechend eigene Referenz darauf einbauen. Am Ende in der Datenbank ist die Tabelle dann schön simpel aufgebaut, es ist bloß je nach Ableitung eine der Fremdschlüssel Null.

ProcessOrTemplate
BIGINT Id
NVARCHAR(MAX) Data
BIGINT ProcessDataId :::

ProcessData
BIGINT Id
NVARCHAR(MAX) Data

TemplateData
BIGINT Id
NVARCHAR(MAX) Data

ListItem
BIGINT M_Id :::

Option 4:
Sowohl Prozess als auch Vorlage sind weiter als Ableitungen einer Basisklasse und mit TPT gemappt. Daneben gibt es auch für die m:n-Zwischentabelle eine Ableitungs-Hierarchie, die konkreten Ableitungen haben dann eine eigene Referenz zum Prozess bzw. zur Vorlage.

Process
BIGINT Id
NVARCHAR(MAX) Data
NVARCHAR(MAX) ProcessData

Template
BIGINT Id
NVARCHAR(MAX) Data
NVARCHAR(MAX) TemplateData

ProcessOrTemplateListItem
BIGINT M_Id :::

===============

Ich persönlich mag Option 1, allerdings sieht die im Moment nicht aus, als wäre sie ohne kranke Hacks möglich.
Als Alternative gefällt mir Option 4 am besten, da ich die komplexen Ableitungen in der Datenbank voneinander getrennt habe und die erzwungene TPH-Tabelle denkbar simpel gehalten wird.

Was denkt ihr dazu?

Beste Grüße

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

W
955 Beiträge seit 2010
vor 5 Jahren

Hallo,

  1. in deiner Option1 brauchst du wahrscheinlich 2 Fremdschlüssel, einmal für Process und für Template.
  2. Ich würde mir genau überlegen ob die sehr fest bindende Vererbung hier das beste Mittel ist. Wenn Template einfach nur eine Kopierschablone ist würde ich zwei getrennte Beziehungen aufsetzen, Process-ProcessItem und Template-TemplateItem
Palladin007 Themenstarter:in
2.080 Beiträge seit 2012
vor 5 Jahren

Hallo witte und danke für deine Antwort

1.
Das wäre dann ja im Prinzip Option 4, oder wie meinst Du das?

2.
Ich brauch leider die Vererbung, da die teils aufwändige Logik auf die gemeinsamen Daten aufbaut. Der Punkt ist nämlich, dass die Vorlage genauso lange wie ein Prozess behandelt werden soll, bis sich Prozess-Bezogene Daten ändern.
Klar könnte ich dafür auch ein Interface definieren, aber wie gut funktioniert das dann noch mit LINQ to SQL? Das müsste ich Mal austesten.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.