使用 LINQ to Entities 进行自然排序
Natural sorting with LINQ to Entities
我尝试使用 LINQ to Entities 实现自然排序,使用等效于此 SQL 语句:
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 to Entities 虽然在模式中添加波浪号 (~)。
它正在生成这样的 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-9]
开头的名称。
String.StartsWith(x)
是一个 string 方法,它检查字符串是否以文字开头,没有模式匹配。 Linq to Entities 翻译此 LIKE 'x%'
,其中 x
是文字字符串,而不是模式。 [
是 LIKE 语句中的一个特殊字符。这意味着它必须使用 LIKE '~[0-9]%' escape '~'
进行转义。 LIKE
运算符允许您指定转义字符,在本例中为 ~
.
我怀疑您不想要以 [0-9]
开头的名称,而是想要以数字开头的名称,即 LIKE '[0-9]%'
。 String.StartsWith 不支持模式,也没有其他 String
方法支持。
一种解决方案是在查询中使用 SqlFunctions.PatIndex 并过滤 return 1 的行。不过我会检查执行计划,因为我怀疑查询会变慢。 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解决方案之一是使用ORDER 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
})
我尝试使用 LINQ to Entities 实现自然排序,使用等效于此 SQL 语句:
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 to Entities 虽然在模式中添加波浪号 (~)。
它正在生成这样的 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-9]
开头的名称。
String.StartsWith(x)
是一个 string 方法,它检查字符串是否以文字开头,没有模式匹配。 Linq to Entities 翻译此 LIKE 'x%'
,其中 x
是文字字符串,而不是模式。 [
是 LIKE 语句中的一个特殊字符。这意味着它必须使用 LIKE '~[0-9]%' escape '~'
进行转义。 LIKE
运算符允许您指定转义字符,在本例中为 ~
.
我怀疑您不想要以 [0-9]
开头的名称,而是想要以数字开头的名称,即 LIKE '[0-9]%'
。 String.StartsWith 不支持模式,也没有其他 String
方法支持。
一种解决方案是在查询中使用 SqlFunctions.PatIndex 并过滤 return 1 的行。不过我会检查执行计划,因为我怀疑查询会变慢。 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解决方案之一是使用ORDER 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
})