2015-01-14 4 views
10

Hintergrundseltsame Verhalten in Entity Framework Linq in String EndsWith Methode

Ich habe eine Tabelle, die nur eine Spalte enthält: Namen. Es gibt nur vier Zeilen drin, sagen

| Name  | 
| test1.com | 
| test2.com | 
| test3.com | 
| test4.com | 

Problem

Wenn ich

var email = "[email protected]"; 
Table.Where(x => email.EndsWith(x.Name)); 

abfragen werde ich eine leere Liste erhalten. Wenn ich aber alle Zeilen abfragen ersten und berechnen Wo im Speicher wie diese

var email = "[email protected]"; 
Table.ToList().Where(x => email.EndsWith(x.Name)); 

Ich werde eine Liste erhalten, enthält nur test2.com was richtig ist.

Die generierte SQL für die erste Abfrage

SELECT "Extent1"."Name" AS "Name" 
FROM "USER"."Table" "Extent1" 
WHERE ((NVL(INSTR(REVERSE(:p__linq__0), REVERSE("Extent1"."Name")), 0)) = 1) 

I ersetzt habe versucht: p__linq__0 mit ‚[email protected]‘ und die Abfrage im sqldeveloper ausgeführt wird, ist das Ergebnis korrekt ist.

Weitere Informationen

Wenn ich EndsWith() zu Enthält() ändern, wird das Problem verschwunden sein. Hier ist die generierte SQL für Enthält()

SELECT "Extent1"."Name" AS "Name" 
FROM "USER"."Table" "Extent1" 
WHERE ((NVL(INSTR(:p__linq__0, "Extent1"."Name"), 0)) > 0) 

Haben Sie eine Ahnung, was mit EndsWith falsch oder Methode REVERSE?

Umwelt

  • EF5.0
  • .NET4.5
  • Oracle11g
  • Diese Zeile betrifft mich 3
+3

Dies ist ein großartiges Beispiel dafür, warum sollten wir die SQL EntityFramework Generiert immer überprüfen, wenn IQueryables direkt mit SQL. Ich kann nicht erklären, warum es das SQL generiert, das es tut ... aber es ist eine allgemeine Praxis geworden, mit fast jedem IQueryable zu überprüfen, das ich produziere. – Derek

Antwort

3

ODP.NET11.2 lösen und ist ein Häufige Fallstricke bei Menschen mit EF:

Der Teil Table.ToList() ist das Schlimmste, weil dies tatsächlich die gesamte Tabelle in den Speicher materialisieren wird und dann die EndsWith in C# ausführen. Diese Zeile:

Table.Where(x => email.EndsWith(x.Name)); 

ich diesen Ansatz warnen würde nur auf allgemeines Prinzip, wie es horrend langsam sein wird, wenn der Tisch in angemessener Größe wächst.Sie können das schwere Heben tun, bevor die Abfrage die Datenbank trifft durch die Domäne aus der E-Mail-Aufteilung aus, wie Sie die Abfrage konstruieren:

var email = "[email protected]"; 

/* You should null check this of course and not just assume a match was found */ 
var domain = Regex.Match(email , "@(.*)").Groups[1].Value; 

/* Note: ToList() materialisation happens at the end */ 
var result = Table.Where(x => x.Name == domain).ToList(); 

Außerdem, wenn Sie auf dem Domain-Namen einer Spalte Speicherung von E-Mail entsprechen müssen , dann wäre meine bevorzugte Vorgehensweise, die E-Mail zu splitten und den Domainnamen in einer separaten Spalte zu speichern, die Sie indexieren und an die Sie sich anpassen. Dies wird skaliert und viel einfacher zu verwalten. Denken Sie daran, dass Daten heutzutage billig sind ... besonders im Vergleich zu nicht-indexierbaren Tabellen-Scans.

Auch nicht vergessen (für beide Szenarien), dass Ihre Datenbank zu CI (Groß- und Kleinschreibung) gesetzt ist

+0

Also ist die Antwort EndsWith wird nicht in EF unterstützt? Ich konnte nicht sehen, dass irgendein Dokument dies beschreibt. Hast du einen Link? – Moozz

+0

Nein, die Antwort ist, was ich oben gesagt habe ... du brauchst es nicht. Extrahieren Sie einfach den Domänennamen in C# und übergeben Sie ihn an die Abfrage. Stellen Sie sicher, dass Sie meine Antwort erneut lesen, da ich denke, dass Sie die Grenzen zwischen C# und sql nicht verstehen. Wenn Sie ToList() in einer EF-Tabellenentität aufrufen, materialisieren Sie (ziehen Sie die gesamte Tabelle in den Speicher), was für die Leistung schrecklich ist und nicht skaliert wird. Klärt das alles auf? Gibt es noch etwas verwirrendes? –

+0

Ich verstehe, dass ToList() alle Zeilen in den Speicher zieht. Ich bin nur neugierig, warum EndsWith nicht funktioniert. Das generierte SQL scheint in Ordnung zu sein, funktioniert aber nicht. Wie auch immer, du hast Recht, dass ich EndsWith nicht verwenden muss. – Moozz

Verwandte Themen