简体   繁体   中英

Natural sorting with LINQ to Entities

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]%' ?

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
                   })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM