2

我試着LINQ實現自然排序到實體,使用這個SQL語句相當於:自然排序與LINQ到實體

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

我的LINQ查詢:

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

LINQ但實體雖然在模式中添加了代字符(〜)。

它生成的SQL查詢是這樣的:

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

如何刪除符號(〜)已追加後,像'〜[0-9]%'

+0

你不要因爲沒有錯。 '['是需要轉義的特殊字符,這就是EF所做的。該查詢是正確的。你要求以確切字符串「[0-9]」開頭的名字。如果你沒有得到結果,那是因爲沒有以精確字符串'[0-9]' –

+0

開始的行,在刪除附加的波形符號(〜)後,我在sql server中得到結果。它沒有逃脫。 – Aby

+1

您的查詢請求以[[0-9] ** ** EXACTLY **開頭的名稱。你要求'[0-9] George'和'[0-9] Pete',而不是'0George'。通過刪除轉義字符,您可以執行完全不同的查詢。你不能使用'StartsWith'的模式匹配。你是否試圖找到以數字開頭的名字? –

回答

3

生成的查詢沒有任何問題,完全按照它的樣子。您的查詢要求輸入以確切字符串[0-9]開頭的名稱。

String.StartsWith(x)是一個字符串方法檢查字符串是否以文字開頭,沒有模式匹配。 Linq to Entities翻譯此LIKE 'x%'其中x是一個文字字符串,而不是一個模式。 [雖然是LIKE語句中的特殊字符。這意味着它必須用LIKE '~[0-9]%' escape '~'進行轉義。 LIKE運算符允許您指定轉義字符,在這種情況下爲~

我懷疑你不希望名字以[0-9]開頭,但是那些以數字開頭的名字,即LIKE '[0-9]%'。 String.StartsWith不支持模式,也沒有另一個String方法。

一個解決方案是在您的查詢中使用SqlFunctions.PatIndex,併爲返回的行過濾。我會檢查執行計劃,因爲我懷疑查詢會變慢。 LIKE '[0-9]%本質上是範圍搜索的所有字符串,從0開始到9之後的字母排除,即A。這意味着服務器可以使用Name上的索引。使用PATINDEX可能需要處理所有行。

不幸的是,SqlFunctions不包含Like或任何類似的方法,將生成LIKE語句模式匹配。

另一種選擇是實際詢問a.Name >="0" && a.Name <"A"的範圍查詢。

更新 - 自然排序

這是XY Problem的情況。實際問題X是如何使用LINQ to Entities執行自然排序。一個自然排序的T-SQL的解決方案是按照下面的順序組合使用公式BY子句與名稱本身,使純文本後的數字顯示,如:

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

不幸的是,這並未不適用於EF,因爲沒有與LIKE相同的模式。

相同的排序可以用PATINDEX,這可通過SqlFunctions.PatIndex功能進行:

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

等效LINQ代碼可能是:

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

感謝Panagiotis,PatIndex在這裏工作:) – Aby