Laden...

[geschlossen] Entity Framework mit Tabellen die sich selbst referenzieren (Hierarchie)

Erstellt von Marco_GR vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.130 Views
M
Marco_GR Themenstarter:in
48 Beiträge seit 2011
vor 10 Jahren
[geschlossen] Entity Framework mit Tabellen die sich selbst referenzieren (Hierarchie)

verwendetes Datenbanksystem: <SQL Server 2008>

Hallo zusammen

ich habe folgendes Problem, welches ich am einfachsten mit folgendem Beispiel erkläre: Using Self Referencing Tables With Entity Framework

Der Tabelleninhalt ist wie im Beispiel:
CategoryID | Name | ParentID
1 | Programming Languages | null
2 | C# | 1
3 | Java | 1

Die Hierarchie, die ich vom EF zurückbekomme:
.1 Programming Languages
. 2 C#
. 3 Java
.2 C#
.3 Java

Erwarten würde ich folgendes:
.1 Programming Languages
. 2 C#
. 3 Java

Ich möchte die Hierarchie an ein WPF TreeView binden, jedoch sind die Entities 2 C# und 3 Java doppelt vorhanden. Warum wird dies von EF so zurückgegeben und gibt es eine Möglichkeit dieses Verhalten zu ändern?

Leider wird der SQL Server HierarchyID-Datentyp vom EF nicht unterstützt, sonst wäre wohl das die Lösung.

Vielen Dank für Eure Hilfe.

Gruss Marco

16.807 Beiträge seit 2008
vor 10 Jahren

Ist C# auch doppelt in der Tabelle, oder nur in der Rückgabe?
Wenn ersteres, dann stimmt Dein Insert nicht.

M
Marco_GR Themenstarter:in
48 Beiträge seit 2011
vor 10 Jahren

@Abt: Nein, in der Tabelle ist der Eintrag C# und Java nur einmal vorhanden. Ich benutze Entity Framework, welches die Inserts selbst generiert.

M
Marco_GR Themenstarter:in
48 Beiträge seit 2011
vor 10 Jahren

Hallo zusammen,

ich kann fast nicht glauben, dass noch niemand zusammen mit Entity Framework mit einer Tabellen welche einen FOREIGN KEY Constraint auf eine Spalte in der gleichen Tabelle hat, zu tun hatte. Wenn doch war die Hierarchie die Euch das EF zurück gab nach Euren Vorstellungen?

Ich habe das Beispiel nachgebaut und als Anhang hinzugefügt. Damit es funktioniert, muss per NuGet Entity Framework installiert werden.

16.807 Beiträge seit 2008
vor 10 Jahren

Wenn doch war die Hierarchie die Euch das EF zurück gab nach Euren Vorstellungen?

Ja habe ich und ja es hat funktioniert.

4.221 Beiträge seit 2005
vor 10 Jahren

Da scheint auf der Root-Ebene die Einschränkung auf ParentID=null zu fehlen.

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

M
Marco_GR Themenstarter:in
48 Beiträge seit 2011
vor 10 Jahren

@Programmierhaus: Vielen Dank, das ist die Lösung. Nach meiner Logik dürften nun nur noch Elemente mit ParentID == null erscheinen, also nur "Programming Languages". Es funktioniert jedoch richtig und C# und Java erscheinen ebenfalls 🤔.

In meinem Fall müsste ich diese where Bedingung bei der Include Methode anwenden, was aber immer noch nicht möglich ist. Meiner Meinung nach ist dies das wichtigste Feature in EF, dass noch fehlt. Da muss ich wohl diese Elemente separat laden.

M
Marco_GR Themenstarter:in
48 Beiträge seit 2011
vor 10 Jahren

Ich dachte, dass mein Problem mit dem Tipp von @Abt erledigt ist, was leider nicht der Fall ist. In meinem Fall habe ich eine Master-Detailansicht. Die Detailobjekte (Entities) sind solche selbstreferenzierende Entities, was eine Hierarchie von Objekten gleichen Typs ergibt. Die Reinfolge dieser Entities in der Baumansicht ist wichtig, darum habe ich ein Property SortIndex hinzugefügt. Wenn nun ein Masterobjekt selektiert wird, werden die Detailobjekte von der Datenbank geladen.

Der Inhalt der Tabelle Category ist folgender:

CategoryId--Name-----------------------SortIndex--ParentId--MasterID
1-------------Programming Languages--1-----------NULL------1
2-------------Java-------------------------3-----------1----------1
3-------------C#-------------------------- 2-----------1----------1
4-------------Pascal-----------------------4-----------2----------1

Als Resultat wünsche ich mir folgendes Ergebnis:

1 Programming Languages
--3 C#
--2 Java
----4 Pascal


master.Categories = context.Categories.Where(c => c.MasterID == master.MasterID).OrderBy(c => c.SortIndex).ToList();

oder


context.Entry(master).Collection(m => m.Categories).Query().OrderBy(c => c.SortIndex).Load();

gibt als Resultat:
1 Programming Languages 1 Unchanged
--3 C# 2 Unchanged
--2 Java 3 Unchanged
----4 Pascal 4 Unchanged
3 C# 2 Unchanged
2 Java 3 Unchanged
--4 Pascal 4 Unchanged
4 Pascal 4 Unchanged
Reihenfolge würde stimmen, jedoch kommen Elemente doppelt und dreifach vor.


master.Categories = context.Categories.Where(c => c.MasterID == master.MasterID && c.ParentId == null).OrderBy(c => c.SortIndex).ToList();

oder


context.Entry(master).Collection(m => m.Categories).Query().Where(c => c.ParentId == null).OrderBy(c => c.SortIndex).Load();

gibt als Resultat:
1 Programming Languages 1 Unchanged

Gibt also wirklich nur Elemente mit ParentId == null zurück. Man könnte natürlich Lazy Loading über "virtual" einschalten, jedoch kann dann die Reihenfolge nicht beeinflusst werden.


master.Categories = context.Categories.Where(c => c.MasterID == master.MasterID && c.ParentId == null).OrderBy(c => c.SortIndex).Include(c => c.Categories).ToList();

gibt als Resultat:
1 Programming Languages 1 Unchanged
--2 Java 3 Modified
--3 C# 2 Modified

Das Element Pascal fehlt, welches sich auf Stufe 3 befinden sollte. Alle Elemente > Stufe 1 sind schon nach dem Laden als Modified markiert. Reihenfolge stimmt nicht.


context.Entry(master).Collection(m => m.Categories).Query().Where(c => c.ParentId == null).OrderBy(c => c.SortIndex).Include(c => c.Categories).Load();

gibt als Resultat:
1 Programming Languages 1 Unchanged
--2 Java 3 Unchanged
--3 C# 2 Unchanged
2 Java 3 Unchanged
3 C# 2 Unchanged

Zu viele Elemente und falsche Reihenfolge.

Die neuste Version des Testprojekts lade ich als Dateianhang hoch, damit die Problematik nachvollzogen werden kann.

Für jede Hilfe von Euch bin ich dankbar, jedoch denke ich mittlerweile, dass das Problem ein Bug in EF ist.

M
Marco_GR Themenstarter:in
48 Beiträge seit 2011
vor 10 Jahren

Habe das Thema als geschlossen markiert, weil laut Aussage eines EF Projekt Mitglieds, das Verhalten so richtig ist, also "By Design".