Reputation: 1018
I've tried to implement natural sorting with LINQ to Entities, using the equivalent of this SQL statement:
ORDER BY case when name like '[0-9]%' then 1 else 0 end, name
My LINQ query is:
query.OrderByDescending(a => a.Name.StartsWith("[0-9]") ? 1 : 0)
LINQ to Entities though is adding a tilde (~) in the pattern.
It's generating an SQL query like this:
SELECT CASE WHEN (Extent1.name LIKE '~[0-9]%' escape '~') THEN 1 ELSE 0 END AS [C1], name
from accounts extent1
order by c1 asc
How can I remove tilde (~) that has been appended after, like '~[0-9]%'?
Upvotes: 2
Views: 2118
Reputation: 131491
There's nothing wrong with the generated query, it's exactly as it should be. Your query asks for names that start with the exact string [0-9]
.
String.StartsWith(x)
is a string method that checks whether a string starts with a literal, without pattern matching. Linq to Entities translates this LIKE 'x%'
where x
is a literal string, not a pattern. [
is a special character in a LIKE statement though. This means that it has to be escaped with LIKE '~[0-9]%' escape '~'
. The LIKE
operator allows you to specify the escape character, in this case ~
.
I suspect that you didn't want names starting with [0-9]
though, but those that start with a digit, ie LIKE '[0-9]%'
. String.StartsWith doesn't support patterns nor is there another String
method that does.
One solution is to use SqlFunctions.PatIndex in your query and filter for rows that return 1. I'd check the execution plan though, because I suspect the query will be slower. LIKE '[0-9]%
is essentially a range search for all strings that start from 0
up to the letter after 9
excluding, ie A
. This means that the server can use indexes on Name
. With PATINDEX it may have to process all rows.
Unfortunately, SqlFunctions
doesn't contain Like
or any similar method that would generate a LIKE
statement with pattern matching.
Another option is to actually ask for a range query with a.Name >="0" && a.Name <"A"
.
UPDATE - NATURAL SORTING
This is a case of the XY Problem. The actual problem X is how to perform natural sorting with LINQ to Entities. One of the T-SQL solutions for natural sorting is to use a formula in the ORDER BY clause in combination with the name itself, to make numbers appear after plain text, eg:
ORDER BY case when name like '[0-9]%' then 1 else 0 end, name
Unfortunately, this doesn't work with EF because there is no equivalent to LIKE
with patterns.
The same ordering can be performed with PATINDEX, which is available through the SqlFunctions.PatIndex function :
order by name, case when PATINDEX('[0-9]%',name)=1 then 1 else 0 end
The equivalent LINQ code could be:
query.OrderBy(a => {
SqlFunctions.PatIndex("[0-9]%",a.Name)==1? 1:0,
a.Name
})
Upvotes: 4