none
EntityFramework 6: Abfragen mit Where-Bedingung tiefer als eine Ebene

    Frage

  • Liebe Foren-Mitglieder,
    ich nutze EntityFramework 6 mit Oracle.ManagedDataAccess, um Daten aus einer Oracle-Datenbank abzufragen. Nun stellt sich für mich die Frage, ob es möglich ist, in der WHERE-Clause mehrere Bedingungen zu formulieren, die mehr als eine Ebene tief sind?

    Angenommen es gibt die folgenden 3 Entitäten:

       public class A
        {
            public List<B> ListOfB { get; }
        }
    
        public class B
        {
            public int B_Id { get; }
            public List<C> ListOfC { get; }
        }
        public class C
        {
            public int C_Id { get; }
            public int C_Value { get; }
        }

    Wie ist es möglich, nach allen ListOfB-Datensätzen der A-Entität zu fragen, für die beispielsweise gilt B_Id == 4 und mit C_Value == 24?

    Bisher versuchte ich:

    List<A> result = null;
    using (var context = new EntityContext())
    {
        IQueryable<T> dbQuery = context.Set<A>().Where(e => e.ListOfB.Any(t => t.B_Id == 4 && t.ListOfC.Any(f => f.C_Value = 24)));
        result = dbQuery.ToList<T>();
    }
    return result

    Die derart erstellte Abfrage führt aber zu einer 'ORA-00904: Invalid identifier'-Ausnahme.

    Vielen Dank!

    Montag, 10. Oktober 2016 09:53

Antworten

  • Hallo,

    eigentlich sollte es ebenso in Oracle funktionieren, wenn das obige SQL rauskommt, denn solche Abfragen sind (Uralt-)Standard.

    Was passiert denn, wenn Du die erzeugte Abfrage dort absetzt?

    Alternativ wäre etwas zu probieren wie ein Join kombiniert mit einem Distinct, was allerdings nicht gerade die schnellste Lösung sein dürfte, wenn die Datenmengen größer werden.

    Gruß Elmar

    • Als Antwort markiert MinimalPark Montag, 10. Oktober 2016 16:12
    Montag, 10. Oktober 2016 15:30

Alle Antworten

  • Hallo,

    Der Fehler ORA-00904 weist darauf hin, dass eine Bezeichnung nicht zum Spaltennamen der jeweiligen Tabelle passt. Du solltest genau prüfen, ob die Bezeichnungen stimmen (ggf. Groß-/Kleinschreibung beachten).

    Ansonsten passt die Abfrage bis auf das <T> hier <A> lauten sollte und bei der Bedingung für C_Value ein "==" nicht "=" stehen müsste.

    Gruß Elmar

    Montag, 10. Oktober 2016 10:36
  • Hallo Elmar,
    vielen Dank für die Antwort.
    Die Spaltennamen sind leider ordnungsgemäß, auch die Groß-/Kleinschreibung ist korrekt (= in Oracle immer groß):

    List<A> result = null;
    using (var context = new EntityContext())
    {
        IQueryable<A> dbQuery = context.Set<A>()
            .Where(e => e.ListOfB.Any(t => t.B_Id == 4 && t.ListOfC.Any(f => f.C_Value == 24)));
        result = dbQuery.ToList<A>();
    }

    Aus der voranstehenden Beispielabfrage generiert EntityFramwork den folgendem SQL-String:

    SELECT 
    "Extent1"."A_ID" AS "A_ID"
    FROM "ICMREP_01"."A_TABLE" "Extent1"
    WHERE ( EXISTS (SELECT 
    	1 AS "C1"
    	FROM ( SELECT 
    		"Extent2"."B_ID" AS "B_ID"
    		FROM "ICMREP_01"."B_TABLE" "Extent2"
    		WHERE ("Extent1"."A_ID" = "Extent2"."A_ID")
    	)  "Project1"
    	WHERE ((4 = "Project1"."B_ID") AND ( EXISTS (SELECT 
    		1 AS "C1"
    		FROM "ICMREP_01"."C_TABLE" "Extent3"
    		WHERE (("Project1"."B_ID" = "Extent3"."B_ID") AND (24 = "Extent3"."C_VALUE"))
    	)))
    ))

    Und dieser führt zur Fehlermeldung: 'ORA-00904: \"Extent1\".\"A_ID\": invalid identifier'.
    Ohne die Bedingung der 2. Ebene (&& t.ListOfC.Any(f => f.C_Value == 24)) funktioniert die Abfrage einwandfrei.
    Ist dieses Problem in EntityFramework zu lösen?

    Freundliche Grüße


    Montag, 10. Oktober 2016 12:38
  • Hallo,

    ich habe hier kein Oracle zur Hand, aber generell ist das SQL richtig, vorausgesetzt es passt zum Schema. Hier das Äquivalent für SQL Server:

    CREATE SCHEMA ICMREP_01;
    GO
    CREATE TABLE ICMREP_01.A_TABLE (A_ID int NOT NULL);
    CREATE TABLE ICMREP_01.B_TABLE (B_ID int NOT NULL, A_ID int NOT NULL);
    CREATE TABLE ICMREP_01.C_TABLE (C_ID int NOT NULL, B_ID int NOT NULL, C_VALUE int NOT NULL);
    GO
    

    Was aber keine Besonderheiten enthält - ein beliebiger numerische Datentyp reicht. Zu beachten wäre inbes., dass die übergeordneten Spalten in B_TABLE und C_TABLE existieren müssen.

    Meckert Oracle trotzdem, sieht es nach Problemen in Oracles EF Implementation aus. Schau dann nach aktualisierten Treibern und ggf. sprich mit deren Support.

    Gruß Elmar

    Montag, 10. Oktober 2016 12:57
  • Vielen Dank Elmar, habe das Beispiel in SQL Server nachgebildet, da funktionniert es problemlos.
    Es scheint prinzipiell so zu sein, dass WHERE-Bedingung in EF im Zusammenspiel mit Oracle nicht über die erste Ebene hinaus definiert werden können.
    Oder irre ich mich hierin?

    Ein Problemlösungsweg wäre natürlich, 2 Abfragen zu generieren mit jeweils einer Where-Bedingung und diese im Anschluß über eine Intersection-Operation zusammenzuführen. Dies ist aber bei großen Datenmengen wenig effizient. Gibt es Alternativen?

    Freundliche Grüße

    Montag, 10. Oktober 2016 15:24
  • Hallo,

    eigentlich sollte es ebenso in Oracle funktionieren, wenn das obige SQL rauskommt, denn solche Abfragen sind (Uralt-)Standard.

    Was passiert denn, wenn Du die erzeugte Abfrage dort absetzt?

    Alternativ wäre etwas zu probieren wie ein Join kombiniert mit einem Distinct, was allerdings nicht gerade die schnellste Lösung sein dürfte, wenn die Datenmengen größer werden.

    Gruß Elmar

    • Als Antwort markiert MinimalPark Montag, 10. Oktober 2016 16:12
    Montag, 10. Oktober 2016 15:30
  • ... die Abfrage direkt gegen die Datenbank führt zur selben Fehlermeldung: 'ORA-00904: \"Extent1\".\"A_ID\": invalid identifier'
    Montag, 10. Oktober 2016 15:34
  • Hallo,

    seltsam, das Oracle das nicht hinkriegen soll... Aber dann bleibt wohl nur, zu experimentieren welcher alternativer Ausdruck (wie oben genannt) zum Ziel führt.

    Gruß Elmar

    Montag, 10. Oktober 2016 16:15
  • Hi,

    nutzt Du CodeFirst oder DatabaseFirst. Wenn ersteres, probier es mal mit DatabaseFirst. Wenn man sich so nach dieser Fehlermeldung ORA-00904 in Verbindung mit dem EF6 umschaut, gibt es diese Probleme recht häufig. Bei den meisten Usern war Abhilfe nur durch Nutzung von DatabaseFirst möglich.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Montag, 10. Oktober 2016 16:46
  • Hallo Elmar,
    ja eigentlich unverständlich, warum dies nicht gehen soll. Denn eigentlich wäre zu vermuten, dass diese Art von Problemstellung häufig sein sollte.

    Aber offensichtlich gibt es tatsächlich eine Limitierung in Oracle, wie hier beschrieben.

    Unabhängig davon aber vielen Dank für die Hilfe.
    Freundlicher Gruß

    Montag, 10. Oktober 2016 16:50
  • Hi,

    welche Oracle Version nutzt Du denn? Wenn ich das richtig gelesen habe, sollte das seit Version 11.2 bzw. 12c eigentlich gehen (letztes Posting in dem Thread)


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Montag, 10. Oktober 2016 16:59
  • Hi Stefan,
    ich nutze CodeFirst, der Grund hierfür ist u.a., um schnell zwischen verschiedenen Schema und Datenbanken innerhalb von Oracle wechseln zu können.
    Als Oracle-Version entwickle ich auf der 11g Express Edition (Release 11.2.0.2.0).

    Freundliche Grüße

    Montag, 10. Oktober 2016 17:08