简体   繁体   中英

EF.Functions.Like in a compiled query could not be translated to SQL equivalent

I am writing a compiled query which takes a DBContext and search string as input and returns a list of Class1 It basically runs 3 filters on the class1 objects and returns a filtered list of class1 objects.

Main query:

var temp = await context.Class1.Where(c => EF.Functions.Like(c.param1, $"%{query}%") && c.param2== 1 && c.param3!= 1).OrderBy(p => EF.Functions.Like(p.param1, $"{query}%") ? 0 : 1).AsNoTracking().ToListAsync();

This actually filters the list and then sorts them in an order where the names starting with the search query are shown before the others. Then

var result = temp.Select(a => new Class2{ T1= a.A1, T2= a.A2, T3= a.A3}).Distinct().Take(10).ToList();

Till now this is the Compiled Query I have wrote:

private static Func<DbContext, string, IEnumerable<Class1>> Search =
            EF.CompileQuery((DbContext context, string query) =>
            context.Class1
            .Where(c => EF.Functions.Like(c.param1, $"%{query}%") 
             && c.param2== 1 
             && c.param3!= 1)
            );

But when this compiled query is called it throws this exception: the linq expression could not be translated

How to solve this?

Update: This is solved now.

private static Func<DbContext, string, IEnumerable<Class2>> Search =
            EF.CompileQuery((DbContextcontext, string query) =>
            context.Class1
            .Where(c => c.param1.ToLower().Contains(query) && c.param2== 1 && c.param3!= 1)
            .OrderBy(p => p.param1.ToLower().StartsWith(query) ? 0 : 1)
            .Select(a => new Class2{ T1 = a.A1, T2 = a.A2, T3 = a.A3 })
            .Take(10).AsNoTracking());
private static Func<DbContext, string, IEnumerable<Class2>> Search =
            EF.CompileQuery((DbContextcontext, string query) =>
            context.Class1
            .Where(c => c.param1.ToLower().Contains(query) && c.param2== 1 && c.param3!= 1)
            .OrderBy(p => p.param1.ToLower().StartsWith(query) ? 0 : 1)
            .Select(a => new Class2{ T1 = a.A1, T2 = a.A2, T3 = a.A3 })
            .Take(10).AsNoTracking());

You seems to be hitting yet another EF Core limitation. The problem is not the EF.Functions.Like method, but the usage of the interpolated string inside, which as you found works inside regular query, but not inside compiled query definition.

The solution/workaround is to use string concatenation in place of string interpolation:

private static Func<DbContext, string, IEnumerable<Class1>> Search =
    EF.CompileQuery((DbContext context, string query) => context.Class1
    .Where(c => EF.Functions.Like(c.param1, "%" + query + "%") // <-- 
     && c.param2== 1 
     && c.param3!= 1)
    );

The resulting SQL query is a bit different, but at least you got a translation.

If you are using EF Core , you don't need using CompileQuery , just use Ef.Function.Like as below

    var users = context.Users.Where(a => EF.Functions.Like(a.FirstName, "%a%")).ToList();

So Rewriting your code in this way would be like this:

    var result= context.Class1
        .Where(c => EF.Functions.Like(c.param1, $"%{query}%")
         && c.param2 == 1
         && c.param3 != 1).ToList();

Updated : If you want to get its result as t-sql, you can use ToQueryString() like this:

  var users = context.Users.Where(a => EF.Functions.Like(a.FirstName, "%a%")).ToQueryString();

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