StartsWith() doesn't translate to Like('abc%') in LINQ

感情迁移 提交于 2019-12-05 12:39:21

The rules for SQL translation in EF Core are still unclear, far from perfect, under discussion and are changing with every even minor release.

The translation of StartsWith, EndsWith and Contains has been discussed and changed several times - for instance, issue #474: Query: Improve translation of String's StartsWith, EndsWith and Contains). The translation of StartsWith has been even changed in the latest official v1.1.2 release, so the v1.1.1 translation

(CHARINDEX(@__name_0, [u0].[Name]) = 1)) OR (@__name_0 = N''))

now will be something like

[u0].[Name] LIKE @__name_0 + '%' AND (CHARINDEX(@__name_0, [u0].[Name]) = 1)) OR (@__name_0 = N''))

The idea is with LIKE condition to allow query optimizer to use the index, and then do the slow filtering with the second condition like before (it's all about handling correctly (similar to C#) the wildcard characters inside the search string as well as empty search string).

So you may try upgrading and see if it helps. The upcoming v2 when released will provide more natural support for db specific operators like LIKE etc.

Another workaround currently (if the above is really the performance bottleneck) is to build the query filtering part directly with SQL and the rest with LINQ (in contrast with EF6, EF Core allows that):

var results = await db.ApplicationUsers
    //.Where(u => u.Name.StartsWith(name) && !u.Deleted && u.AppearInSearch)
    .FromSql("select * from ApplicationUsers where Name like {0}", name + "%")
    .Where(!u.Deleted && u.AppearInSearch)
    .OrderByDescending(u => u.Verified)
    .ThenBy(u => u.DateAdded) // Added to prevent duplication of results in different pages
    .Skip(page * recordsInPage)
    .Take(recordsInPage)
    .Select(u => new UserSearchResult()
    {
        Name = u.Name,
        Verified = u.Verified,
        PhotoURL = u.PhotoURL,
        UserID = u.Id,
        Subdomain = u.Subdomain
     }).ToListAsync();

Note that FromSql method supports parameters, so SQL injection should not be a concern. Still you need to know the table name, column names and the concrete database SQL syntax - something that is supposed to be abstracted by the ORM for you.

Entity Framework provides special function EF.Functions.Like to use it for LINQ expressions with standard SQL LIKE syntax. For StartWith pattern an expression will be like this:

var likeExpression = name+"%";
... await db.ApplicationUsers.Where(u => EF.Functions.Like(u.Name,likeExpression)...
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!