Hier ist ein bestätigter Fehlerbericht mit Oracle: Ссылка
Situation
Als ich eine .Include
Kette in meinem Repository benutzte, bemerkte ich, dass ich merkwürdige Ergebnisse erhielt - meistens, dass die abgefragten Werte aus den falschen Feldern stammten (der Name würde zum Beispiel in der Beschreibung enden - aber in In der Datenbank sind alle Werte korrekt, sie werden erst nach der Abfrage falsch angezeigt). Ich änderte die Namen, so dass die Beziehungen offensichtlicher sind, aber die Struktur ist die gleiche. Ich bekomme immer die falschen Werte für das zugehörige CrewMember und deren relativen Rang und Abstand. Anscheinend gibt es einen Feldnamen, der in CrewMember gleich dem Rang ist, und der Wert dieses Feldes in Rank entspricht dem Wert in CrewMember. Wenn zum Beispiel Rank eine Beschreibung hätte und Crew Crew auch, dann wäre die Beschreibung von Rang für das CrewMember die Beschreibung des CrewMember.
Entity Framework kann keine wohlgeformten Abfragen über eine Tiefe von 2 hinaus ausführen, wenn ähnliche Felder als Ergebnis des SQL Server-Anbieters MySQL Connector / NET definiert wurden, der join
-Anweisungen nicht richtig formatiert.
Definitionen
Dies ist eine Klassendefinition, die eine Datenbanktabelle modelliert. Ich benutze C # ASP.NET MVC 3 mit dem Entity Framework 4.1 und der MySQL Connector / NET Version 6.5
%Vor%Abfrage
Dies ist der Code, der die Datenbank abfragt und die Abfrage- und .Include-Aufrufe enthält.
%Vor% Sind diese .Include
-Aufrufe gut gebildet? Habe ich etwas verpasst?
Das ist ziemlich komplex, also wenn Sie irgendwelche Fragen haben, lassen Sie es mich bitte in Kommentaren wissen und ich werde versuchen, etwas zu klären, was ich vielleicht weggelassen habe.
Wie kann ich Entity Framework verwenden, um bei Verwendung von MySQL Connector / NET eine wohlgeformte Abfrage eines Objektgraphen über eine Tiefe von 2 hinaus zu erhalten?
Bearbeitungen
Hier ist die generierte Abfrage:
%Vor%Erläuterung
Die Verwendung von Include-1-1-Beziehungen stellt kein Problem dar, wenn man auf diese Art und Weise "bohrt". Das Problem scheint jedoch zu entstehen, wenn es im Rahmen der Bohrungen 1-viele Beziehungen gibt. Das Bohren ist notwendig, um eifrig beladen zu werden.
Die erste Projektion, entity => entity.Ships.Select(s => s.CrewMembers
, gibt eine Liste der CrewMembers zurück, die zu jedem Schiff gehören. Dies gibt das Diagramm korrekt zurück, in dem ein Hafen eine Liste von Schiffen mit jeweils einer Liste von Besatzungsmitgliedern enthält.
Die zweite Projektion CrewMembers.Select(cm => cm.Rank
gibt jedoch nicht das richtige Stück des Graphen zurück. Felder beginnen gemischt zu werden, und alle Felder, die denselben Namen haben, werden aus irgendeinem Grund in das übergeordnete Feld übernommen. Dies führt zu inkonsistenten Ergebnissen und, was noch wichtiger ist, zu schlechten Daten. Die Tatsache, dass keine Fehler geworfen werden, macht es noch schlimmer, da dies nur durch eine Laufzeitprüfung festgestellt werden kann.
Wenn es eine Möglichkeit gäbe, eine stark typisierte einzelne Antwort (im Gegensatz zu einer Liste) von der ersten Projektion zu bekommen, wäre vielleicht die zweite nicht notwendig. Wie ich jetzt glaube, liegt das Problem in der ersten Projektion, die eine Liste zurückgibt. Wenn die zweite Projektion versucht, basierend auf dieser Liste statt von einem einzelnen Objekt zu projizieren, wird der logische Fehler eingeführt.
Wenn es sich bei CrewMembers nicht um eine ICollection handelt, sondern nur um ein CrewMember, dann liefert diese verschachtelte Projektion tatsächlich die korrekten Daten. Dies ist jedoch eine vereinfachte Version dieses Problems und es ist leider, was fast alle Tests aus den verschiedenen Blogs, Tutorials, Posts, Artikeln und Dokumenten, die ich überprüft habe versucht, um dieses Problem zu lösen scheinen gemacht worden.
Bearbeiten
Der folgende Test wurde mit SQL Server und SqlClient
als Provider durchgeführt. Die Tatsache, dass das Problem mit SQL Server nicht reproduzierbar ist, wirft die Frage auf, ob der von Ihnen verwendete MySql
-Provider einen Fehler enthält, durch den falsches SQL für Ihre LINQ-Abfrage erstellt wird. Es sieht aus wie das gleiche Problem wie in diese Frage , wo das Problem mit einem% co_de aufgetreten ist % provider ebenfalls und konnte nicht mit MySql
/ SQL Server reproduziert werden.
Ich bekomme immer wieder falsche Werte für das zugehörige CrewMember und ihr relativer Rang und ihre Clearance. Es scheint, wenn es einen Feldnamen gibt Das ist in CrewMember derselbe wie Rank, dann der Wert dieses Feldes in Rank wird der Wert in CrewMember. Zum Beispiel, wenn Rank hatte eine Beschreibung, Crew Crew und dann die Beschreibung von Rank Für das CrewMember wäre die CrewMember Beschreibung.
Ich habe das Beispiel fett gedruckt (mit EF 4.3.1) und kann das Problem nicht reproduzieren:
%Vor%Die Ausgabe ist:
Nach deiner Beschreibung in Fettschrift sollte ich haben: Crew Member 1 Beschreibung="Rang A" und das gleiche Chaos für die anderen 3 Besatzungsmitglieder. Aber ich habe das nicht.
Ist in meinem Testprogramm etwas anders als in Ihrem Code, wo Sie den Fehler haben?
Bearbeiten
Das generierte SQL für die Abfrage (siehe Zeile SqlClient
im obigen Quelltext, der folgende ist der Inhalt von var sqlString = query.ToString();
) ist:
Zunächst wissen Sie, dass es query = query.Include(...).Include(...)
sein muss, richtig?
Solange Sie die letzten 2 ausführen, brauchen Sie nicht die ersten 2. Sowohl Schiffe als auch CrewMembers werden von der zweiten 2 geladen. Haben Sie gerade das versucht?
%Vor%Sie können sql profiler auch immer starten, um genau zu sehen, welche Abfrage ef an die db sendet. Ich würde keinen Fehler erwarten, der Eigenschaftswerte von verschiedenen Objekten im Graphen vertauscht, wenn Sie nur die 3. und 4. Includes ausführen.
Wie es aussieht, ist es nicht möglich, das Diagramm in einer Reise mit EF zu erhalten, wenn Sie MySQLConnector / NET verwenden. Sehen Sie sich diesen bestätigten Fehlerbericht mit Orcale an . Was getan werden muss, ist
%Vor% Dieser Code entspricht dem Beispiel, ist aber offensichtlich nur ein Beispiel und würde eine bessere Implementierung benötigen, um tatsächlich ausgeführt zu werden. Dies ist der Ansatz, den ich verwende, bis ich die .Include
EF-Funktionalität überladen oder verbessern kann, um den gesamten Graphen in einem Durchgang zu erhalten.
Es ist nicht ideal, die Daten für mehrere Fahrten zu erhalten, aber es funktioniert.
Tags und Links c# linq mysql entity-framework-4.1 eager-loading