本文记录一下 动态生成linq查询条件
实现代码
var filterList = LinqFilterHelper.GetFilterList<Model>(searchModel);
var lambda = LinqFilterHelper.CombineExpressions(filterList.ToArray());
var list = list.Where(lambda.Compile()).ToList();
相关帮助类 LinqFilterHelper
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="searchModel"></param>
/// <returns></returns>
public static List<Expression<Func<T, Boolean>>> GetFilterList<T>(object searchModel)
{
try
{
var dynamicSearchModel = JsonHelper.JsonToObject<Models.Models.DynamicSearchModel>(JsonHelper.ObjectToJson(searchModel));
if (dynamicSearchModel == null || dynamicSearchModel.ConditionList == null)
return null;
// 创建参数表达式
// 创建一个表示类型T的参数表达式,名称为"x"。
ParameterExpression param = Expression.Parameter(typeof(T), "x");
var list = new List<Expression<Func<T, Boolean>>>();
var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
foreach (var fieldCondition in dynamicSearchModel.ConditionList)
{
Expression<Func<T, Boolean>> combinedCondition = null;
// 临时存储or条件
var tempOrFilterList = new List<Expression<Func<T, Boolean>>>();
foreach (var condition in fieldCondition.Conditions)
{
var fieldFilter = GetFieldFilter<T>(props, param, fieldCondition.Field, condition.Type, condition.FirstValue, condition.SecondValue);
if (fieldFilter != null)
{
tempOrFilterList.Add(fieldFilter);
}
}
if (tempOrFilterList.Count > 0)
{
if (combinedCondition == null)
{
combinedCondition = tempOrFilterList[0];
}
if (tempOrFilterList.Count > 1)
{
for (int i = 1; i < tempOrFilterList.Count; i++)
{
var orElse = Expression.OrElse(combinedCondition.Body, tempOrFilterList[i].Body);
combinedCondition = Expression.Lambda<Func<T, Boolean>>(orElse, combinedCondition.Parameters[0]);
}
}
else
{
combinedCondition = tempOrFilterList[0];
}
list.Add(combinedCondition);
}
}
return list;
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 生成具体查询语句
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="param">参数表达式</param>
/// <param name="fieldName">字段名</param>
/// <param name="logicType">查询类型 eq/in/between</param>
/// <param name="firstValue">查询值</param>
/// <param name="secondValue">查询次值</param>
/// <returns></returns>
private static Expression<Func<T, bool>> GetFieldFilter<T>(PropertyInfo[] props, ParameterExpression param, string fieldName, string logicType, object firstValue, object secondValue)
{
var prop = props.FirstOrDefault(p => p.Name.ToLower() == fieldName.ToLower());
Expression<Func<T, bool>> condition = null;
if (prop != null)
{
// 创建一个表示属性或字段访问的 属性表达式, 将参数param和过滤条件的键(filter.Key)关联起来
MemberExpression member = Expression.PropertyOrField(param, fieldName);
// 创建一个包含过滤条件值的 常量表达式
ConstantExpression constant = Expression.Constant(firstValue);
switch (logicType.ToLower())
{
case "eq":
MethodInfo equalsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string), typeof(StringComparison) });
MethodCallExpression equalsCall = Expression.Call(member, equalsMethod, constant, Expression.Constant(StringComparison.OrdinalIgnoreCase));
// 创建 Lambda 表达式
condition = Expression.Lambda<Func<T, bool>>(equalsCall, param);
break;
case "in":
// 创建一个包含过滤条件值的 常量表达式
constant = Expression.Constant(JsonHelper.JsonToObject<List<string>>(JsonHelper.ObjectToJson(firstValue)).Select(s => s.ToLowerInvariant()));
// 创建将属性转换为小写的表达式
MethodInfo toLowerMethod = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
MethodCallExpression toLowerCall = Expression.Call(member, toLowerMethod);
// 获取 Contains 方法的 MethodInfo,并泛型化为 string 类型
MethodInfo containsMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.First(m => m.Name == "Contains" && m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(string)); // 泛型化为集合元素类型
// 构建 MethodCallExpression,调用 Enumerable.Contains 方法,传入集合和属性 表示 collection.Contains(property.ToLower())
MethodCallExpression containsCall = Expression.Call(
containsMethod,
constant,
toLowerCall
);
// 创建 Lambda 表达式
condition = Expression.Lambda<Func<T, bool>>(containsCall, param);
break;
case "lt":
if (prop.PropertyType.Name.ToLower() == "string")
{
// 创建将属性转换为小写的表达式
MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);
// 创建string.Compare方法调用表达式
MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));
// 创建比较表达式(GreaterThanOrEqual)
Expression lessThan = Expression.LessThan(comparison, Expression.Constant(0));
condition = Expression.Lambda<Func<T, bool>>(lessThan, param);
}
else
{
// 创建大于等于表达式
BinaryExpression body = Expression.LessThan(param, constant);
// 创建lambda表达式
condition = Expression.Lambda<Func<T, bool>>(body, param);
}
break;
case "lte":
if (prop.PropertyType.Name.ToLower() == "string")
{
// 创建将属性转换为小写的表达式
MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);
// 创建string.Compare方法调用表达式
MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));
// 创建比较表达式(GreaterThanOrEqual)
Expression lessThanOrEqual = Expression.LessThanOrEqual(comparison, Expression.Constant(0));
condition = Expression.Lambda<Func<T, bool>>(lessThanOrEqual, param);
}
else
{
// 创建大于等于表达式
BinaryExpression body = Expression.LessThanOrEqual(param, constant);
// 创建lambda表达式
condition = Expression.Lambda<Func<T, bool>>(body, param);
}
break;
case "gt":
if (prop.PropertyType.Name.ToLower() == "string")
{
// 创建将属性转换为小写的表达式
MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);
// 创建string.Compare方法调用表达式
MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));
// 创建比较表达式
Expression greaterThan = Expression.GreaterThan(comparison, Expression.Constant(0));
condition = Expression.Lambda<Func<T, bool>>(greaterThan, param);
}
else
{
// 创建大于等于表达式
BinaryExpression body = Expression.GreaterThan(param, constant);
// 创建lambda表达式
condition = Expression.Lambda<Func<T, bool>>(body, param);
}
break;
case "gte": //大于等于
if (prop.PropertyType.Name.ToLower() == "string")
{
// 创建将属性转换为小写的表达式
MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);
// 创建string.Compare方法调用表达式
MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
Expression comparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));
// 创建比较表达式
Expression greaterThanOrEqual = Expression.GreaterThanOrEqual(comparison, Expression.Constant(0));
condition = Expression.Lambda<Func<T, bool>>(greaterThanOrEqual, param);
}
else
{
// 创建大于等于表达式
BinaryExpression body = Expression.GreaterThanOrEqual(param, constant);
// 创建lambda表达式
condition = Expression.Lambda<Func<T, bool>>(body, param);
}
break;
case "between":
// 创建一个包含过滤条件值的 常量表达式
ConstantExpression secondConstant = Expression.Constant(secondValue);
if (prop.PropertyType.Name.ToLower() == "string")
{
// 创建将属性转换为小写的表达式
MethodInfo toLowerMethod1 = typeof(string).GetMethod("ToLowerInvariant", Type.EmptyTypes);
// 创建ToLowerInvariant方法调用表达式(对于member、constant和secondConstant)
MethodCallExpression toLowerMember = Expression.Call(member, toLowerMethod1!);
MethodCallExpression toLowerConstant = Expression.Call(constant, toLowerMethod1!);
MethodCallExpression toLowerSecondConstant = Expression.Call(secondConstant, toLowerMethod1!);
// 创建string.Compare方法调用表达式
MethodInfo compareMethodInfo = typeof(string).GetMethod("Compare", new[] { typeof(string), typeof(string), typeof(StringComparison) });
Expression greaterComparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerConstant, Expression.Constant(StringComparison.Ordinal));
// 创建 大于等于 比较表达式
Expression greaterThanOrEqual = Expression.GreaterThanOrEqual(greaterComparison, Expression.Constant(0));
Expression lessComparison = Expression.Call(compareMethodInfo, toLowerMember, toLowerSecondConstant, Expression.Constant(StringComparison.Ordinal));
// 创建 小于等于 比较表达式
Expression lessThanOrEqual = Expression.LessThanOrEqual(lessComparison, Expression.Constant(0));
// 组合两个比较表达式为逻辑与(AndAlso)
BinaryExpression andExpression = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual);
condition = Expression.Lambda<Func<T, bool>>(andExpression, param);
}
else
{
// 创建大于等于表达式
BinaryExpression greaterThanOrEqual = Expression.GreaterThanOrEqual(param, constant);
BinaryExpression lessThanOrEqual = Expression.LessThanOrEqual(param, secondConstant);
// 组合两个比较表达式为逻辑与(AndAlso)
BinaryExpression andExpression = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual);
// 创建lambda表达式
condition = Expression.Lambda<Func<T, bool>>(andExpression, param);
}
break;
default:
condition = null;
break;
}
}
return condition;
}
/// <summary>
/// 条件汇总
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expressions"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static Expression<Func<T, bool>> CombineExpressions<T>(params Expression<Func<T, bool>>[] expressions)
{
if (expressions == null || expressions.Length == 0)
{
throw new ArgumentException("No expressions provided.");
}
// 第一个表达式作为起点
Expression<Func<T, bool>> combined = expressions[0];
// 逐个拼接剩余的表达式
for (int i = 1; i < expressions.Length; i++)
{
// 创建 AndAlso 表达式
var andAlso = Expression.AndAlso(combined.Body, expressions[i].Body);
// 使用 LambdaExpression.Update 方法来更新参数和主体
combined = Expression.Lambda<Func<T, bool>>(andAlso, combined.Parameters[0]);
}
return combined;
}
相关实体类
/// <summary>
/// 动态查询类
/// </summary>
public class DynamicSearchModel
{
/// <summary>
/// 排序
/// </summary>
public List<SortModel> SortList { get; set; }
/// <summary>
///
/// </summary>
public List<TableHeaderModel> TableHead { get; set; }
/// <summary>
/// 描述 : 查询条件列表 当条件列表为空或不填时,则不设查询条件
/// 空值 : False
/// 默认 :
/// </summary>
public List<ConditionFieldModel> ConditionList { get; set; }
}
/// <summary>
/// 字段条件
/// </summary>
public class ConditionFieldModel
{
/// <summary>
/// 描述 : 字段
/// 空值 : False
/// 默认 :
/// </summary>
public string Field { get; set; }
/// <summary>
/// 描述 : 条件
/// 空值 : False
/// 默认 :
/// </summary>
public List<ConditionModel> Conditions { get; set; }
}
/// <summary>
/// 条件
/// </summary>
public class ConditionModel
{
/// <summary>
/// 描述 : 条件类型 eq:等于,ne:不等于,lt:小于,lte:小于等于,gt:大于,gte:大于等于,like:模糊匹配,in:包含, notin:不包含,between:在...之间
/// 空值 : False
/// 默认 :
/// </summary>
public string Type { get; set; }
/// <summary>
/// 描述 : 该参数可为任意值,当类型为boolean时,只可以使用eq类型。当类型为in时,需传输Array对象
/// 空值 : False
/// 默认 :
/// </summary>
public object FirstValue { get; set; }
/// <summary>
/// 描述 : 该参数只在类型为between时使用,为between的第二个值
/// 空值 : False
/// 默认 :
/// </summary>
public object SecondValue { get; set; }
}