C# 铁心动态滤波器
我一直在使用表达式树为EF核心查询使用动态筛选器类,一切看起来都很好,筛选器正在工作,我可以传递一个筛选器集合,它也可以工作,但是当我查看SQL语句时,它正在查询整个表并将筛选器应用于结果集合,下面是我的类C# 铁心动态滤波器,c#,linq,expression-trees,ef-core-2.1,C#,Linq,Expression Trees,Ef Core 2.1,我一直在使用表达式树为EF核心查询使用动态筛选器类,一切看起来都很好,筛选器正在工作,我可以传递一个筛选器集合,它也可以工作,但是当我查看SQL语句时,它正在查询整个表并将筛选器应用于结果集合,下面是我的类 public static class QueryExpressionBuilder { private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains", new[]
public static class QueryExpressionBuilder
{
private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
#region DynamicWhere
/// <summary>Where expression generator.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="filters">The filters.</param>
/// <returns></returns>
public static Expression<Func<T, bool>> GetExpression<T>(IList<Filter> filters)
{
if (filters.Count == 0)
return null;
ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;
if (filters.Count == 1)
exp = GetExpression(param, filters[0]);
else if (filters.Count == 2)
exp = GetExpression<T>(param, filters[0], filters[1]);
else
{
while (filters.Count > 0)
{
var f1 = filters[0];
var f2 = filters[1];
if (exp == null)
exp = GetExpression<T>(param, filters[0], filters[1]);
else
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1]));
filters.Remove(f1);
filters.Remove(f2);
if (filters.Count == 1)
{
exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));
filters.RemoveAt(0);
}
}
}
return Expression.Lambda<Func<T, bool>>(exp, param);
}
/// <summary>Comparision operator expression generator.</summary>
/// <param name="param">The parameter.</param>
/// <param name="filter">The filter.</param>
/// <returns></returns>
private static Expression GetExpression(ParameterExpression param, Filter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
var type = member.Type;
ConstantExpression constant;
switch (type.Name)
{
case "Int32":
constant = Expression.Constant(Convert.ToInt32(filter.Value));
break;
case "String":
default:
constant = Expression.Constant(filter.Value);
break;
}
// ConstantExpression constant = Expression.Constant(filter.Value);
switch (filter.Operation)
{
case Op.Equals:
return Expression.Equal(member, constant);
case Op.GreaterThan:
return Expression.GreaterThan(member, constant);
case Op.GreaterThanOrEqual:
return Expression.GreaterThanOrEqual(member, constant);
case Op.LessThan:
return Expression.LessThan(member, constant);
case Op.LessThanOrEqual:
return Expression.LessThanOrEqual(member, constant);
case Op.Contains:
return Expression.Call(member, ContainsMethod, constant);
case Op.StartsWith:
return Expression.Call(member, StartsWithMethod, constant);
case Op.EndsWith:
return Expression.Call(member, EndsWithMethod, constant);
}
return null;
}
/// <summary>And logic connector expression generator.</summary>
/// <typeparam name="T"></typeparam>
/// <param name="param">The parameter.</param>
/// <param name="filter1">The filter1.</param>
/// <param name="filter2">The filter2.</param>
/// <returns></returns>
private static BinaryExpression GetExpression<T>(ParameterExpression param, Filter filter1, Filter filter2)
{
var bin1 = GetExpression(param, filter1);
var bin2 = GetExpression(param, filter2);
return Expression.AndAlso(bin1, bin2);
}
#endregion
}
非常感谢您的帮助。主要问题不在于课程,而在于您使用它的方式:
var whereDeleg = QueryExpressionBuilder.GetExpression<Tax>(filters).Compile();
var myList = _dbContext.MyEntity.Where(whereDeleg).ToList();
或者只是
var myList = _dbContext.MyEntity.Where(QueryExpressionBuilder.GetExpression<Tax>(filters)).ToList();
能够简单地使用(并尽量减少出错的机会):
旁注:主表达式生成器方法实现过于复杂,并且会破坏传递的输入
过滤器列表。可以简化如下(不存在上述缺陷):
公共静态表达式GetExpression(IEnumerable筛选器)
{
var param=表达式参数(类型(T),“T”);
变量体=过滤器
.Select(filter=>GetExpression(param,filter))
.DefaultIfEmpty()
.骨料(表示为AndAlso);
返回body!=null?表达式。Lambda(body,param):null;
}
主要问题不在于类,而在于您使用它的方式:
var whereDeleg = QueryExpressionBuilder.GetExpression<Tax>(filters).Compile();
var myList = _dbContext.MyEntity.Where(whereDeleg).ToList();
或者只是
var myList = _dbContext.MyEntity.Where(QueryExpressionBuilder.GetExpression<Tax>(filters)).ToList();
能够简单地使用(并尽量减少出错的机会):
旁注:主表达式生成器方法实现过于复杂,并且会破坏传递的输入过滤器列表。可以简化如下(不存在上述缺陷):
公共静态表达式GetExpression(IEnumerable筛选器)
{
var param=表达式参数(类型(T),“T”);
变量体=过滤器
.Select(filter=>GetExpression(param,filter))
.DefaultIfEmpty()
.骨料(表示为AndAlso);
返回body!=null?表达式。Lambda(body,param):null;
}
生成的sql是什么,期望的是什么?为什么我觉得它是关于和的?如果是,请参阅。您可以使用Gridify库。生成的sql是什么,期望的是什么?为什么我觉得它是关于和的?如果是,请参阅。您可以使用Gridify库。
var myList = _dbContext.MyEntity.Where(QueryExpressionBuilder.GetExpression<Tax>(filters)).ToList();
public static IQueryable<T> Where<T>(this IQueryable<T> source, IList<Filter> filters)
{
var predicate = GetExpression<T>(filters);
return predicate != null ? source.Where(predicate) : source;
}
var myList = _dbContext.MyEntity.Where(filters).ToList();
public static Expression<Func<T, bool>> GetExpression<T>(IEnumerable<Filter> filters)
{
var param = Expression.Parameter(typeof(T), "t");
var body = filters
.Select(filter => GetExpression(param, filter))
.DefaultIfEmpty()
.Aggregate(Expression.AndAlso);
return body != null ? Expression.Lambda<Func<T, bool>>(body, param) : null;
}