Benutzer mit den meisten Antworten
LINQ-Abfrage mit Where-Bedingung bei Include einer Trackable-Collection....

Frage
-
Hallo
ich habe eine LINQ-Abfrage (LINQ-to-Entities) mit einer Where-Bedingung, die ich zur Laufzeit zusammensetze; jetzt ist noch ein weitere Include einer Entität hinzugekommen, dass eine Trackable-collection liefert. Von dieser möchte ich aber nur eine bestimme Art von Datensatz haben. Ist es möglich diese in der Where-Bedingung zu definieren?
Hier mal mein LINQ-statement:
IEnumerable<TerminWarteliste> query = this.GetBaseQuery().Include("TerminWartelisteKategorie") .Include("TerminWarteliste_PatFall") .Include("TerminWarteliste_PatFall.Fall_Patient") .Include("TerminWarteliste_PatFall.Fall_Patient.HauptAdresse") .Include("TerminWarteliste_PatFall.FallTexte"); IQueryable<TerminWarteliste> whereQuery = query.AsQueryable(); if (kategoriePrimaryKey != null) whereQuery = whereQuery.Where(p => p.Kategorie == kategoriePrimaryKey).AsQueryable(); if (!string.IsNullOrEmpty(dringlichkeitsKategorie)) whereQuery = whereQuery.Where(p => p.DringlichkeitsKategorie == dringlichkeitsKategorie).AsQueryable(); if(!string.IsNullOrEmpty(ambulantStationaer)) whereQuery = whereQuery.Where(p => p.TerminWarteliste_PatFall.FallArt == ambulantStationaer).AsQueryable(); if(erledigt != null) whereQuery = whereQuery.Where(p => p.Erledigt == erledigt).AsQueryable(); whereQuery = whereQuery.Where(p => p.TerminWarteliste_PatFall.FallImPool == false).AsQueryable(); whereQuery = whereQuery.Where(p => p.TerminWarteliste_PatFall.FallTexte.Where(x => x.TextArt == diagnoseTextArt)).AsQueryable();
es geht um den letzten Include("TerminWarteliste_PatFall.FallTexte") - von diesen sogenannten Fall-Texten möchte ich nur eine bestimmte Textart geliefert bekommen - dies hätte ich mit dem letzten whereQuere-statement verusucht, in der trackable-collection nochmals einzugrenzen.........aber so funktioniert das nicht.
Wie kann ich denn bei dieser Art von LINQ-Abfrage auf einer Trackable-Collection nochmals eine Einschränkung treffen ??
Kann mir dazu bitte jemand weiterhelfen ??
Danke schon mal & schönen Gruß
Michael
Michael Erlinger
Antworten
-
Hallo Michael,
Es geht um den letzten Include("TerminWarteliste_PatFall.FallTexte") - von diesen sogenannten Fall-Texten möchte ich nur eine bestimmte Textart geliefert bekommen.
Mit Include() erreichst Du ein eager loading der assoziierten Entities, nichts mehr und nichts weniger. Das bedeutet aber auch dass Du immer ALLE Listenelemente einer assoziierten 1:N-Beziehung mit der Entity zurückbekommen wirst. Alles andere würde den Objektgraphen in einen ungültigen Zustand versetzen.
In Deiner dynamischen Abfrage kannst Du also mittels Where-Abfrage höchstens erreichen, dass eine Untermenge aller TerminWarteliste-Entities zurückgegeben wird (unter Verwendung von Any()), aber nie eine Entity mit gefilterter Navigations-Eigenschaft:whereQuery = whereQuery.Where(p => p.TerminWarteliste_PatFall.FallTexte.Any(x => x.TextArt == diagnoseTextArt)).AsQueryable();
Diese Abfrage würde also alle TerminWarteliste-Instanzen zurückgeben die mindestens ein FallText enthalten, auf den diagnoseTextArt zutrifft.
Hier ein Northwind-basiertes Beispiel, das die Grenzen von EF etwas forciert, indem zunächst anonym projiziert, dann das Ergebnis materialisiert und als IQueryable<Orders> zurückgegeben wird:
var query = (from o in context.Orders select new { Order = o, Order_Details = o.Order_Details.Where(d => d.Quantity > 22) }); var materialisiert = query.AsEnumerable(); var ergebnis = materialisiert.Select(anon => anon.Order).AsQueryable();
Beachte bitte, dass die Ergebnisauflistung Orders für Artikel mit Quantität > 22 enthält sowie Artikel mit leerer Order_Details-Auflistung dort, wo keines der Artikel eine Bestellmenge > 22 aufwies.
[Willst Du das noch mehr eingrenzen, so helfen nur Projektionen und DTOs weiter. Damit wären wir aber beim manuellen change tracking und die Wirkung von Include() ist gleich null sobald Projektionen verwendet werden.]
Du könntest aber auch erwägen, ob Du nicht lieber IQueryable<FallTexte> statt IQueryable<TerminWarteliste> zurückgeben möchtest. Schließlich kannst Du, bei einem gut designten Modell über die Properties in alle Richtungen navigieren. Nur die Form (shape) der Daten wäre eine andere.
In Zusammenhang mit Silverlight-Anwendungen sind weitere Optionen möglich.s.a. Update relationships when saving changes of EF4 POCO objects:
http://stackoverflow.com/questions/3635071/update-relationships-when-saving-changes-of-ef4-poco-objectsUsing self tracking entities with Silverlight 4 and Entity Framework 4:
http://blogs.infosupport.com/blogs/alexb/archive/2010/08/24/using-self-tracking-entities-with-silverlight-4-and-entity-framework-4.aspxGruss
Marcel- Bearbeitet Marcel RomaModerator Freitag, 25. Februar 2011 08:36 Code-Beispiel
- Als Antwort markiert M.Erlinger Montag, 7. März 2011 10:02
-
Hallo Michael,
Natürlich könnte man auch JOIN verwenden. Rein technisch gesehen ist es möglich (und für den SQL-Programmierer sicherlich sehr geläufig):
var query = from o in context.Orders.Include("Orders.Order_Details") join d in Order_Details on o.OrderID equals d.OrderID where d.Quantity > 10 select o; foreach(var order in query) { order.Order_Details.Load(); // order.Order_Details verwenden ... }
(mit vielen Spielarten...)
Aber schau Dir das bitte genauer an. Was siehst Du? Obwohl wir Include verwenden, müssen die Details manuell nachgeladen werden (über zusätzliche Roundtrips zur Datenbank, und in Deinem Fall wären es einige mehr...).
Man könnte alternativ eine nested query verwenden, evtl. mit Projektion in einen anonymen Typ und evtl. mit impliziter Rückkonversion zu Orders. Aber löst dies das grundsätzliche Problem? Nein, das grundsätzliche Problem liegt in der Art und Weise wie das Model strukturiert wurde. Wenn "FallText (mit bestimmter TextArt) optional sind", dann sollten sie auch eine eigene Entität darstellen (in Unkenntnis der Domäne kann ich natürlich nicht mehr dazu schreiben).
Wie sagte Zlatko Michailov in seinem Blog so passend?
"A well defined query against a well defined entity data model does not need JOIN."
http://blogs.msdn.com/b/esql/archive/2007/11/01/entitysql_5f00_tip_5f00_1.aspx
Gruss
Marcel- Als Antwort markiert M.Erlinger Montag, 7. März 2011 10:02
Alle Antworten
-
Hallo Michael,
Es geht um den letzten Include("TerminWarteliste_PatFall.FallTexte") - von diesen sogenannten Fall-Texten möchte ich nur eine bestimmte Textart geliefert bekommen.
Mit Include() erreichst Du ein eager loading der assoziierten Entities, nichts mehr und nichts weniger. Das bedeutet aber auch dass Du immer ALLE Listenelemente einer assoziierten 1:N-Beziehung mit der Entity zurückbekommen wirst. Alles andere würde den Objektgraphen in einen ungültigen Zustand versetzen.
In Deiner dynamischen Abfrage kannst Du also mittels Where-Abfrage höchstens erreichen, dass eine Untermenge aller TerminWarteliste-Entities zurückgegeben wird (unter Verwendung von Any()), aber nie eine Entity mit gefilterter Navigations-Eigenschaft:whereQuery = whereQuery.Where(p => p.TerminWarteliste_PatFall.FallTexte.Any(x => x.TextArt == diagnoseTextArt)).AsQueryable();
Diese Abfrage würde also alle TerminWarteliste-Instanzen zurückgeben die mindestens ein FallText enthalten, auf den diagnoseTextArt zutrifft.
Hier ein Northwind-basiertes Beispiel, das die Grenzen von EF etwas forciert, indem zunächst anonym projiziert, dann das Ergebnis materialisiert und als IQueryable<Orders> zurückgegeben wird:
var query = (from o in context.Orders select new { Order = o, Order_Details = o.Order_Details.Where(d => d.Quantity > 22) }); var materialisiert = query.AsEnumerable(); var ergebnis = materialisiert.Select(anon => anon.Order).AsQueryable();
Beachte bitte, dass die Ergebnisauflistung Orders für Artikel mit Quantität > 22 enthält sowie Artikel mit leerer Order_Details-Auflistung dort, wo keines der Artikel eine Bestellmenge > 22 aufwies.
[Willst Du das noch mehr eingrenzen, so helfen nur Projektionen und DTOs weiter. Damit wären wir aber beim manuellen change tracking und die Wirkung von Include() ist gleich null sobald Projektionen verwendet werden.]
Du könntest aber auch erwägen, ob Du nicht lieber IQueryable<FallTexte> statt IQueryable<TerminWarteliste> zurückgeben möchtest. Schließlich kannst Du, bei einem gut designten Modell über die Properties in alle Richtungen navigieren. Nur die Form (shape) der Daten wäre eine andere.
In Zusammenhang mit Silverlight-Anwendungen sind weitere Optionen möglich.s.a. Update relationships when saving changes of EF4 POCO objects:
http://stackoverflow.com/questions/3635071/update-relationships-when-saving-changes-of-ef4-poco-objectsUsing self tracking entities with Silverlight 4 and Entity Framework 4:
http://blogs.infosupport.com/blogs/alexb/archive/2010/08/24/using-self-tracking-entities-with-silverlight-4-and-entity-framework-4.aspxGruss
Marcel- Bearbeitet Marcel RomaModerator Freitag, 25. Februar 2011 08:36 Code-Beispiel
- Als Antwort markiert M.Erlinger Montag, 7. März 2011 10:02
-
Hallo Marcel
vielen Dank für Deine Rückmeldung!!
Noch eine Frage nachträglich - wäre es nicht möglich via JOIN() in dem LINQ-Beispiel von mir zu arbeiten ?? d.h. einen outer-Join auf meine "FallText"-Entität, wo dann nur eine bestimmte TextArt selektiert wird.......
Zu Deinem Vorschlag über die IQueryable<FallTexte> zu gehen - dies hätte ich probiert, aber leider kann ich das nicht anwenden, weil FallText (mit bestimmter TextArt) optional sind; und dann würden für die Liste Daten fehlen.
Schönen Gruß
Michael
Michael Erlinger- Bearbeitet M.Erlinger Samstag, 26. Februar 2011 20:48 Zusatz
-
Hallo Michael,
Natürlich könnte man auch JOIN verwenden. Rein technisch gesehen ist es möglich (und für den SQL-Programmierer sicherlich sehr geläufig):
var query = from o in context.Orders.Include("Orders.Order_Details") join d in Order_Details on o.OrderID equals d.OrderID where d.Quantity > 10 select o; foreach(var order in query) { order.Order_Details.Load(); // order.Order_Details verwenden ... }
(mit vielen Spielarten...)
Aber schau Dir das bitte genauer an. Was siehst Du? Obwohl wir Include verwenden, müssen die Details manuell nachgeladen werden (über zusätzliche Roundtrips zur Datenbank, und in Deinem Fall wären es einige mehr...).
Man könnte alternativ eine nested query verwenden, evtl. mit Projektion in einen anonymen Typ und evtl. mit impliziter Rückkonversion zu Orders. Aber löst dies das grundsätzliche Problem? Nein, das grundsätzliche Problem liegt in der Art und Weise wie das Model strukturiert wurde. Wenn "FallText (mit bestimmter TextArt) optional sind", dann sollten sie auch eine eigene Entität darstellen (in Unkenntnis der Domäne kann ich natürlich nicht mehr dazu schreiben).
Wie sagte Zlatko Michailov in seinem Blog so passend?
"A well defined query against a well defined entity data model does not need JOIN."
http://blogs.msdn.com/b/esql/archive/2007/11/01/entitysql_5f00_tip_5f00_1.aspx
Gruss
Marcel- Als Antwort markiert M.Erlinger Montag, 7. März 2011 10:02