I'd like to create a generic extension method which allow me to use Full-text search.
● The code below works:
IQueryable<MyEntity> query = Repository.AsQueryable();
if (!string.IsNullOrEmpty(searchCondition.Name))
query = query.Where(e => EF.Functions.Contains(e.Name, searchCondition.Name));
return query.ToList();
● But I want a more-generic-way so I create the following extension method
public static IQueryable<T> FullTextContains<T>(this IQueryable<T> query, Func<T, string> keySelector, string value)
{
return query.Where(e => EF.Functions.Contains(keySelector(e), value));
}
When I call the exxtension method like below, I got an exception
IQueryable<MyEntity> query = Repository.AsQueryable();
if (!string.IsNullOrEmpty(searchCondition.Name))
query = query.FullTextContains(e => e.Name, searchCondition.Name);
return query.ToList();
> System.InvalidOperationException: 'The LINQ expression 'DbSet > .Where(c => __Functions_0 > .Contains( > _: Invoke(__keySelector_1, c[MyEntity]) > , > propertyReference: __value_2))' could not be translated. Either rewrite the query in a form that > can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), > AsAsyncEnumerable(), ToList(), or ToListAsync(). > See https://go.microsoft.com/fwlink/?linkid=2101038 for more information >
How do I "rewrite the query in a form that can be translated" as the Exception suggested?
Your are falling into the typical
IQueryable<>trap by using delegates (Func<>) instead of expressions (Expression<Func<>). You can see that difference in the lambda arguments of everyQueryableextension method vs correspondingEnumerablemethod. The difference is that the delegates cannot be translated (they are like unknown methods), while the expressions can.So in order to do what you want, you have to change the signature of the custom method to use expression(s):
But now you have implementation problem because C# does not support syntax for "invoking" expressions similar to delegates, so the following
does not compile.
In order to do that you need at minimum a small utility for composing expressions like this:
Use
ApplyorApplyTodepending of what type of expression you have. Other than that they do the same.In your case, the implementation of the method with
Expression<Func<T, string>> keySelectorwould be