2

Ich habe versucht, mit LINQ to Entities natürliche Sortierung zu implementieren, um das Äquivalent von dieser SQL-Anweisung:Natürliche Sortierung mit LINQ to Entities

ORDER BY case when name like '[0-9]%' then 1 else 0 end, name 

Meine LINQ-Abfrage ist:

query.OrderByDescending(a => a.Name.StartsWith("[0-9]") ? 1 : 0) 

LINQ zu Entities fügt jedoch eine Tilde (~) in das Muster ein.

Es ist eine SQL-Abfrage wie folgt zu erzeugen:

SELECT CASE WHEN (Extent1.name LIKE '~[0-9]%' escape '~') THEN 1 ELSE 0 END AS [C1], name 
     from accounts extent1 
     order by c1 asc 

Wie kann ich Tilde entfernen (~), die nach dem beigefügten wurde, wie '~ [0-9]%'?

+0

Sie dies nicht tun, weil da ist nichts falsch. '[' 'ist ein Sonderzeichen, das es zu verlassen gilt, und genau das macht EF. Die Abfrage ist korrekt wie sie ist. Sie haben nach Namen gefragt, die mit der exakten Zeichenfolge '[0-9]' beginnen. Wenn Sie keine Ergebnisse erhalten, liegt das daran, dass es keine Zeile gibt, die mit dem exakten String '[0-9]' –

+0

beginnt. Ich erhalte das Ergebnis in sql server nach dem Entfernen der angehängten Tilde (~). Es ist nicht entkommen. – Aby

+1

Ihre Abfrage fragt nach Namen, die mit '[0-9]' ** GENAU ** beginnen. Sie fragen nach '[0-9] George' und' [0-9] Pete', nicht nach '0George'. Durch das Entfernen des Escape-Zeichens führen Sie eine komplett andere Abfrage aus. Sie können den Mustervergleich nicht mit 'StartsWith' verwenden. Hast du versucht, Namen zu finden, die mit einer Nummer beginnen? –

Antwort

3

Es ist nichts falsch mit der generierten Abfrage, es ist genau so, wie es sein sollte. Ihre Abfrage fragt nach Namen, die mit der exakten Zeichenfolge [0-9] beginnen.

String.StartsWith(x) ist eine Zeichenfolge Methode, die überprüft, ob eine Zeichenfolge mit einem Literal ohne Mustervergleich beginnt. Linq to Entities übersetzt dies LIKE 'x%' wobei x eine literale Zeichenfolge, kein Muster ist. [ ist jedoch ein Sonderzeichen in einer LIKE-Anweisung. Dies bedeutet, dass es mit LIKE '~[0-9]%' escape '~' maskiert werden muss. Mit dem Operator LIKE können Sie das Escape-Zeichen angeben, in diesem Fall ~.

Ich vermute, dass Sie keine Namen wollten, die mit [0-9] beginnen, aber diejenigen, die mit einer Ziffer beginnen, also LIKE '[0-9]%'. String.StartsWith unterstützt keine Muster und es gibt auch keine andere String-Methode.

Eine Lösung besteht darin, in Ihrer Abfrage SqlFunctions.PatIndex zu verwenden und nach Zeilen zu filtern, die 1 zurückgeben. Ich würde jedoch den Ausführungsplan überprüfen, weil ich vermute, dass die Abfrage langsamer sein wird. LIKE '[0-9]% ist im Wesentlichen eine Bereichssuche für alle Zeichenfolgen, die von 0 bis zu dem Buchstaben nach 9 mit Ausnahme von A beginnen. Dies bedeutet, dass der Server Indizes unter Name verwenden kann. Bei PATINDEX müssen möglicherweise alle Zeilen verarbeitet werden.

Leider SqlFunctions enthält nicht Like oder eine ähnliche Methode, die eine LIKE-Anweisung mit Mustervergleich generieren würde.

Eine andere Möglichkeit besteht darin, tatsächlich eine Bereichsabfrage mit a.Name >="0" && a.Name <"A" anzufordern.

UPDATE - NATURAL SORTIER-

Dies ist ein Fall des XY Problem. Das eigentliche Problem X ist, wie eine natürliche Sortierung mit LINQ zu Entitäten durchgeführt wird. Einer der T-SQL-Lösungen für natürliche Sortierung ist eine Formel, in der ORDER BY-Klausel in Verbindung mit dem Namen, selbst zu verwenden Zahlen nach Klartext erscheinen zu lassen, zum Beispiel:

ORDER BY case when name like '[0-9]%' then 1 else 0 end, name 

Leider ist diese doesn Ich arbeite nicht mit EF, weil es kein LIKE mit Mustern gibt.

Die gleiche Anordnung kann mit PATINDEX durchgeführt werden, die Funktion zur Verfügung durch die SqlFunctions.PatIndex ist:

order by name, case when PATINDEX('[0-9]%',name)=1 then 1 else 0 end 

Der entsprechende Code LINQ könnte sein:

query.OrderBy(a => { 
        SqlFunctions.PatIndex("[0-9]%",a.Name)==1? 1:0, 
        a.Name 
        }) 
+0

Danke Panagiotis, PatIndex hat hier funktioniert :) – Aby