Reputation: 61
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());
Upvotes: 2
Views: 4031
Reputation: 205759
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.
Upvotes: 3
Reputation: 61
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());
Upvotes: 1
Reputation: 1507
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();
Upvotes: 0