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