动态拼接LINQ查询条件的解决方案
来源:互联网 发布:淘宝代销退货流程 编辑:程序博客网 时间:2024/05/01 10:33
开发中,需要根据用户选择的过滤条件从数据库中查询数据。过滤条件包括等于(”==”)、不等于(“!=”)、大于(“>”)、小于(”<”)、大于等于(“>=”)、小于等于(“<=”)、包含(”in”)、不包含(”out”)八种。过滤条件之间可以是“AND”和“OR”两种关系。过滤条件支持的数据类型有整型和字符串等。用户选择的过滤条件通过json数据提交给后端,后端反序列化后得到过滤条件对象,该对象是FilterModel类的实例,下面是FilterModel类的定义。
public class FilterModel { public string column { get; set; }//过滤条件中使用的数据列 public string action { get; set; }//过滤条件中的操作:==、!=等 public string logic { get; set; }//过滤条件之间的逻辑关系:AND和OR public string value { get; set; }//过滤条件中的操作的值 public string dataType { get; set; }//过滤条件中的操作的字段的类型 }
数据库操作使用ADO.NET EF技术,查询使用Linq。而Linq的扩展方法接收的是一个lambda表达式作为查询条件。那么怎样可以将用户选择的查询条件转换成需要的lambda表达式呢?本文给出了自己的解决方案。
首先,定义下面的泛型方法GetFilterExpression,该方法完成lambda表达式的拼接。GetFilterExpression方法中泛型参数T为需要操作的数据库表对象,输入参数为FilterModel类的实例集合,包含用户选择的所有条件,遍历该集合,调用CreateLambda()方法生成条件对应的lambda表达式,虽有根据条件之间的关系是“AND”还是“OR”完成lambda表达式的拼接工作。
public static Expression<Func<T, bool>> GetFilterExpression<T>(List<FilterModel> filterConditionList) { Expression<Func<T, bool>> condition = null; try { if (filterConditionList != null && filterConditionList.Count > 0) { foreach (FilterModel filterCondition in filterConditionList) { Expression<Func<T, bool>> tempCondition = CreateLambda<T>(filterCondition); if (condition == null) { condition = tempCondition; } else { if ("AND".Equals(filterCondition.logic)) { condition = condition.And(tempCondition); } else { condition = condition.Or(tempCondition); } } } } } catch (Exception ex) { LogHelper.WriteLogException("获取筛选条件异常:" + ex.Message); } return condition; }
接下来,介绍CreateLambda()方法的逻辑,该方法完成过滤条件到lambda表达式的生成操作。
public static Expression<Func<T, bool>> CreateLambda<T>(FilterModel filterCondition) { var parameter = Expression.Parameter(typeof(T), "p");//创建参数i var constant = Expression.Constant(filterCondition.value);//创建常数 MemberExpression member = Expression.PropertyOrField(parameter, filterCondition.column); if ("=".Equals(filterCondition.action)) { return Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter); } else if ("!=".Equals(filterCondition.action)) { return Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter); } else if (">".Equals(filterCondition.action)) { return Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter); } else if ("<".Equals(filterCondition.action)) { return Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter); } else if (">=".Equals(filterCondition.action)) { return Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter); } else if ("<=".Equals(filterCondition.action)) { return Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter); } else if ("in".Equals(filterCondition.action) && "1".Equals(filterCondition.dataType)) { return GetExpressionWithMethod<T>("Contains", filterCondition); } else if ("out".Equals(filterCondition.action) && "1".Equals(filterCondition.dataType)) { return GetExpressionWithoutMethod<T>("Contains", filterCondition); } else { return null; } }
CreateLambda()方法根据判断条件的类型,调用Expression的Equal、NotEqual、GreaterThan、LessThan、LessThanOrEqual、GreaterThanOrEqual方法来生成lambda表达式,而对于”包含”和”不包含”,需要调用字符串的Contains()方法来完成。而这部分逻辑在GetExpressionWithMethod()和GetExpressionWithoutMethod()方法中实现。
“不包含”是在可看成是” 包含”的否定(Not)。
public static Expression<Func<T, bool>> GetExpressionWithMethod<T>(string methodName, FilterModel filterCondition) { ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p"); MethodCallExpression methodExpression = GetMethodExpression(methodName, filterCondition.column, filterCondition.value, parameterExpression); return Expression.Lambda<Func<T, bool>>(methodExpression, parameterExpression); } public static Expression<Func<T, bool>> GetExpressionWithoutMethod<T>(string methodName, FilterModel filterCondition) { ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p"); MethodCallExpression methodExpression = GetMethodExpression(methodName, filterCondition.column, filterCondition.value, parameterExpression); var notMethodExpression = Expression.Not(methodExpression); return Expression.Lambda<Func<T, bool>>(notMethodExpression, parameterExpression); } /// <summary> /// 生成类似于p=>p.values.Contains("xxx");的lambda表达式 /// parameterExpression标识p,propertyName表示values,propertyValue表示"xxx",methodName表示Contains /// 仅处理p的属性类型为string这种情况 /// </summary> /// <param name="methodName"></param> /// <param name="propertyName"></param> /// <param name="propertyValue"></param> /// <param name="parameterExpression"></param> /// <returns></returns> private static MethodCallExpression GetMethodExpression(string methodName, string propertyName, string propertyValue, ParameterExpression parameterExpression) { var propertyExpression = Expression.Property(parameterExpression, propertyName); MethodInfo method = typeof(string).GetMethod(methodName, new[] { typeof(string) }); var someValue = Expression.Constant(propertyValue, typeof(string)); return Expression.Call(propertyExpression, method, someValue); }
最后,介绍一下拼接lambda表达式的实现代码。LinqBuilder类提供 Or()和And()来拼接关系是”且”和”或”的lambda表达式。这部分代码来源于网络。
public static class LinqBuilder { /// <summary> /// 默认True条件 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Expression<Func<T, bool>> True<T>() { return f => true; } /// <summary> /// 默认False条件 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Expression<Func<T, bool>> False<T>() { return f => false; } /// <summary> /// 拼接 OR 条件 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="exp"></param> /// <param name="condition"></param> /// <returns></returns> public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exp, Expression<Func<T, bool>> condition) { var inv = Expression.Invoke(condition, exp.Parameters.Cast<Expression>()); return Expression.Lambda<Func<T, bool>>(Expression.Or(exp.Body, inv), exp.Parameters); } /// <summary> /// 拼接And条件 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="exp"></param> /// <param name="condition"></param> /// <returns></returns> public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> exp, Expression<Func<T, bool>> condition) { var inv = Expression.Invoke(condition, exp.Parameters.Cast<Expression>()); return Expression.Lambda<Func<T, bool>>(Expression.And(exp.Body, inv), exp.Parameters); } }
- 动态拼接LINQ查询条件的解决方案
- linq 动态拼接查询条件 扩展方法
- linq 动态拼接查询条件 扩展方法
- Linq动态拼接条件
- 使用反射让linq实现动态查询, 类似拼接sql语句的where 条件
- Linq动态条件查询
- LINQ To SQL 拼接查询条件
- Linq 联合查询条件快捷拼接方法
- 查询条件的拼接
- linq动态多条件查询
- 【整理】Linq to Entity 动态拼接查询条件(重点是OR)
- Linq的条件查询
- 送上本人的一个LINQ多表关联动态条件查询解决方案(请大家指正)
- linq to sql的多条件动态查询(上)
- linq to sql的多条件动态查询(下)
- linq to sql的多条件动态查询
- linq to sql的多条件动态查询(上)
- 根据条件查询动态拼接sql语句
- 利用node.js搭建简易DASH直播系统
- 11.12acm培训2 Problem E: 字符串的判断
- 盘点物联网领域常用的6大传感器
- jQuery data()
- kmalloc、vmalloc、malloc的区别
- 动态拼接LINQ查询条件的解决方案
- Camera.cullingMask常用操作
- 279. Perfect Squares
- Linux6 fo OracleRAC install
- 枚举BootDriverReinitialization
- URL优化之IIS7如何开启伪静态
- cas-单点登录逻辑模拟学习
- ExpandableList的用法
- LightOJ-1198-greedy