Reputation: 48
I'm using Syncfusion's Grid component in ASP.NET Core project. When sorting, filtering and paginating the grid view it performs LINQ-operations to my IQueryable data source.
When searching text fields, it uses .Contains(string) method, which can't be translated to SQL query and will be evaluated locally.
Is there any way to force EF Core to alter the LINQ query (or to do it by myself) to use .EF.Functions.Like(column, string) instead, because it can be translated to SQL?
var dataSource = ...;
var operation = new QueryableOperation();
// Sorting
if (dm.Sorted != null)
{
dataSource = operation.PerformSorting(dataSource, dm.Sorted);
}
// Filtering
if (dm.Where != null)
{
// PerformFiltering uses .Contains(), which I don't want
dataSource = operation.PerformFiltering(dataSource, dm.Where, dm.Where[0].Operator);
}
// At this point, I want to alter LINQ to use EF.Functions.Like instead of Contains.
var count = dataSource.Count();
// Paging
if (dm.Skip != 0)
{
dataSource = operation.PerformSkip(dataSource, dm.Skip);
}
// Paging
if (dm.Take != 0)
{
dataSource = operation.PerformTake(dataSource, dm.Take);
}
return dm.RequiresCounts ? Json(new { result = dataSource, count }) : Json(dataSource);
Upvotes: 2
Views: 1974
Reputation: 16150
You can modify ExpressionTree
before execution and replace "".Contains()
calls with EF.Functions.Like("", "")
:
public static class LinqExtensions
{
public static IQueryable<T> FixQuery<T>(this IQueryable<T> query)
{
return query.Provider.CreateQuery<T>(
new FixQueryVisitor().Visit(query.Expression)
);
}
class FixQueryVisitor : ExpressionVisitor
{
private readonly MethodInfo _likeMethod = ExtractMethod(() => EF.Functions.Like(string.Empty, string.Empty));
private static MethodInfo ExtractMethod(Expression<Action> expr)
{
MethodCallExpression body = (MethodCallExpression)expr.Body;
return body.Method;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.DeclaringType == typeof(string) && node.Method.Name == "Contains")
{
return Expression.Call(this._likeMethod, Expression.Constant(EF.Functions), node.Object, node.Arguments[0]);
}
return base.VisitMethodCall(node);
}
}
}
[...]
dataSource = dataSource.FixQuery();
Upvotes: 1