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
Ist C# auch doppelt in der Tabelle, oder nur in der Rückgabe?
Wenn ersteres, dann stimmt Dein Insert nicht.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
@Abt: Nein, in der Tabelle ist der Eintrag C# und Java nur einmal vorhanden. Ich benutze Entity Framework, welches die Inserts selbst generiert.
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.
Wenn doch war die Hierarchie die Euch das EF zurück gab nach Euren Vorstellungen?
Ja habe ich und ja es hat funktioniert.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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...
@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.
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.
Habe das Thema als geschlossen markiert, weil laut Aussage eines EF Projekt Mitglieds, das Verhalten so richtig ist, also "By Design".