相信在使用EF的时候对查询条件或者排序上的处理令人心烦,下面我们就来动态拼接表达式解决这一问题

当我们在查询中使用Where的时候可以看到如下参数

下面我们就来扩展 Expression<Func<T,bool>> 这个参数

第一步: 建立处理功能类

首先我们要创建一个查询条件转化为表达式的泛型功能类 如 UosoExpressionParser<T> 至于为什么要用泛型类目的很明确就是为了适配不同的模型参数

转化条件为表达式 那么处理一个方法来接受条件 返回表达式,条件可以按照自己的模式去设置

 public Expression<Func<T, bool>> ParserConditions(IEnumerable<UosoConditions> conditions)
{
//将条件转化成表达是的Body
var query = ParseExpressionBody(conditions);
return Expression.Lambda<Func<T, bool>>(query, parameter);
}
 public class UosoConditions
{
/// <summary>
/// 字段名称
/// </summary>
public string Key { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 值类型
/// </summary>
public string ValueType { get; set; }
/// <summary>
///
/// </summary>
public UosoOperatorEnum Operator { get; set; }
}

第二步: 条件转表达式具体处理

具体去实现  ParseExpressionBody 条件 枚举提供操作方式 如:(like 、 = 、!= 、>   、<  、>=  、<=  、in 、 between)

private Expression ParseExpressionBody(IEnumerable<UosoConditions> conditions)
{
if (conditions == null || conditions.Count() == )
{
return Expression.Constant(true, typeof(bool));
}
else if (conditions.Count() == )
{
return ParseCondition(conditions.First());
}
else
{
Expression left = ParseCondition(conditions.First());
Expression right = ParseExpressionBody(conditions.Skip());
return Expression.AndAlso(left, right);
}
}
 private Expression ParseCondition(UosoConditions condition)
{
ParameterExpression p = parameter;
Expression key = Expression.Property(p, condition.Key);
Expression value = Expression.Constant(condition.Value);
switch (condition.Operator)
{
case UosoOperatorEnum.Contains:
return Expression.Call(key, typeof(string).GetMethod("Contains",new Type[] { typeof(string) }), value);
case UosoOperatorEnum.Equal:
return Expression.Equal(key, Expression.Convert(value, key.Type));
case UosoOperatorEnum.Greater:
return Expression.GreaterThan(key, Expression.Convert(value, key.Type));
case UosoOperatorEnum.GreaterEqual:
return Expression.GreaterThanOrEqual(key, Expression.Convert(value, key.Type));
case UosoOperatorEnum.Less:
return Expression.LessThan(key, Expression.Convert(value, key.Type));
case UosoOperatorEnum.LessEqual:
return Expression.LessThanOrEqual(key, Expression.Convert(value, key.Type));
case UosoOperatorEnum.NotEqual:
return Expression.NotEqual(key, Expression.Convert(value, key.Type));
case UosoOperatorEnum.In:
return ParaseIn(p, condition);
case UosoOperatorEnum.Between:
return ParaseBetween(p, condition);
default:
throw new NotImplementedException("不支持此操作");
}
}

这里对 In  和between 做了特殊处理

private Expression ParaseBetween(ParameterExpression parameter, UosoConditions conditions)
{
ParameterExpression p = parameter;
Expression key = Expression.Property(p, conditions.Key);
var valueArr = conditions.Value.Split(',');
if (valueArr.Length != )
{
throw new NotImplementedException("ParaseBetween参数错误");
}
try
{
int.Parse(valueArr[]);
int.Parse(valueArr[]);
}
catch {
throw new NotImplementedException("ParaseBetween参数只能为数字");
}
Expression expression = Expression.Constant(true, typeof(bool));
//开始位置
Expression startvalue = Expression.Constant(int.Parse(valueArr[]));
Expression start = Expression.GreaterThanOrEqual(key, Expression.Convert(startvalue, key.Type)); Expression endvalue = Expression.Constant(int.Parse(valueArr[]));
Expression end = Expression.GreaterThanOrEqual(key, Expression.Convert(endvalue, key.Type));
return Expression.AndAlso(start, end);
}
  private Expression ParaseIn(ParameterExpression parameter, UosoConditions conditions)
{
ParameterExpression p = parameter;
Expression key = Expression.Property(p, conditions.Key);
var valueArr = conditions.Value.Split(',');
Expression expression = Expression.Constant(true, typeof(bool));
foreach (var itemVal in valueArr)
{
Expression value = Expression.Constant(itemVal);
Expression right = Expression.Equal(key, Expression.Convert(value, key.Type));

expression = Expression.Or(expression, right);
}
return expression;
}

第三步: 扩展分页、排序、查询条件

扩展 IQueryable<T> 就OK了,下面是我扩展的查询 排序 分页处理

扩展查询

public static IQueryable<T> QueryConditions<T>(this IQueryable<T> query, IEnumerable<UosoConditions> conditions)
{
var parser = new UosoExpressionParser<T>();
var filter = parser.ParserConditions(conditions);
return query.Where(filter);
}

扩展多条件排序

 public static IQueryable<T> OrderConditions<T>(this IQueryable<T> query, IEnumerable<UosoOrderConditions> orderConditions)
{
foreach (var orderinfo in orderConditions)
{
var t = typeof(T);
var propertyInfo = t.GetProperty(orderinfo.Key);
var parameter = Expression.Parameter(t);
Expression propertySelector = Expression.Property(parameter, propertyInfo); var orderby = Expression.Lambda<Func<T, object>>(propertySelector, parameter);
if (orderinfo.Order == OrderSequence.DESC)
query = query.OrderByDescending(orderby);
else
query = query.OrderBy(orderby); }
return query;
}

扩展分页

public static IQueryable<T> Pager<T>(this IQueryable<T> query, int pageindex, int pagesize,out int itemCount)
{
itemCount = query.Count();
return query.Skip((pageindex - ) * pagesize).Take(pagesize);
}

扩展基本完成了,接下来就是使用方式 下面是我写的查询分页方式

第四步: 具体使用方式

 public IList<IdentityUser> GetPagedList2(IEnumerable<UosoConditions>  conditions,IEnumerable<UosoOrderConditions> orderConditions,int pageIndex, int pageSize,out int itemcount)
{
return _userManager.Users.AsNoTracking().QueryConditions(conditions).OrderConditions(orderConditions).Pager(pageIndex, pageSize, out itemcount).ToList();
}

你需要构建相关的查询排序集合类就行了 如下:

List<UosoConditions> uosoConditions = new List<UosoConditions>() {
new UosoConditions { Key = "UserName", Operator = UosoOperatorEnum.Contains, Value = "1,3", ValueType = "string" }
};
List<UosoOrderConditions> orderConditions = new List<UosoOrderConditions> {
new UosoOrderConditions{
Key="UserName",
Order = OrderSequence.DESC
},
new UosoOrderConditions{
Key="PhoneNumber",
Order = OrderSequence.DESC
}
};
            int itemcount = ;
var list = _userServices.GetPagedList2(uosoConditions, orderConditions, pageindex, pagesize, out itemcount);

第五步:结合前端分页样式实现整体(之前的有介绍)

ViewBag.Option = new UosoPagerOption()
{
ItemCount = itemcount,
PageSize = pagesize,
PageIndex = pageindex,
CountNum = ,
Url = Request.Path.Value,
Query = Request.Query
};

以上是实现分页的全部过程,这里值得注意的是 在 like查询 Contains的时候,在.NetCore中需要如下这样写,不然可能会出现反射多次被实例化的问题

typeof(string).GetMethod("Contains",new Type[] { typeof(string) }) 

如果是.Net Framework 中 为如下方式

typeof(string).GetMethod("Contains")

.NetCore 使用 Linq 动态拼接Expression表达式条件来实现 对EF、EF Core 扩展查询排序操作的更多相关文章

  1. 分享动态拼接Expression表达式组件及原理

    前言 LINQ大家都知道,用起来也还不错,但有一个问题,当你用Linq进行搜索的时候,你是这样写的 var query = from user in db.Set<User>()      ...

  2. Asp.net Core C#进行筛选、过滤、使用PredicateBuilder进行动态拼接lamdba表达式树并用作条件精准查询,模糊查询

    在asp.net core.asp.net 中做where条件过滤筛选的时候写的长而繁琐不利于维护,用PredicateBuilder进行筛选.过滤.LInq配合Ef.core进行动态拼接lamdba ...

  3. 动态拼接lambda表达式树

    前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dapperLambda按条件查询时是传入表 ...

  4. 用PredicateBuilder实现Linq动态拼接查询

    在使用Linq查询的时候,特别是如果你在使用Entiry Framwork,有时会遇到动态查询的情况(客户的查询条件是不固定的拼接查询).我们能想到的第一方案应该是拼接SQL,的确这样是可以达到我们的 ...

  5. 【转】EntityFramework动态组合Lambda表达式作为数据筛选条件,代替拼接SQL语句

    传统的操作数据库方式,筛选数据需要用StringBuilder拼接一大堆的WHERE子句. 在Entity Framework中,代码稍有不慎就会造成巨大性能消耗,如: using(var db=ne ...

  6. Lambda表达式动态拼接(备忘)

    EntityFramework动态组合Lambda表达式作为数据筛选条件,代替拼接SQL语句 分类: C# Lambda/Linq Entity Framework 2013-05-24 06:58 ...

  7. 表达式树动态拼接lambda

    动态拼接lambda表达式树   前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dappe ...

  8. 动态拼接表达式——Expression

    我们在项目中会遇到以下查询需求吗? 比如需要查询出满足以下条件的会员: 条件组一:30-40岁的男性会员 条件组二:20-30岁的女性会员 条件组三:60-80岁性别未知的会员 条件组内是并且关系,但 ...

  9. linq里lambda写的join查询,并附加动态拼接的条件,条件为enum类型的查询

    因为查询条件不固定的原因,sql式的linq查询没法动态拼接条件. 网上搜的资料整理之后终于解决. 参考资料: enum使用 http://blog.csdn.net/slowlifes/articl ...

随机推荐

  1. 【loj114】k大异或和 线性基+特判

    题目描述 给由 $n​$ 个数组成的一个可重集 $S​$ ,每次给定一个数 $k​$ ,求一个集合 $T⊆S​$ ,使得集合 $T​$ 在 $S​$ 的所有非空子集的不同的异或和中,其异或和 $T_1 ...

  2. Integration Guide

    This document, along with the samples and Javadoc™ in the IBM Sametime Software Development Kit (SDK ...

  3. [代码]--其他信息: ORA-01400: 无法将 NULL 插入

    这个错误其实就是oracle数据库的某列约束为 not null,但在插入值的时候插入了控制,无论是null和"",它都识别为空 有两种方法: 1.修改数据库字段约束为允许为空 2 ...

  4. 前端学习 -- Css -- overflow

    子元素默认是存在于父元素的内容区中,理论上讲子元素的最大可以等于父元素内容区大小.如果子元素的大小超过了父元素的内容区,则超过的大小会在父元素以外的位置显示,超出父元素的内容,我们称为溢出的内容.父元 ...

  5. github使用记录

    背景:一直以来,对github既向往又排斥,是因为感觉高大尚有感觉很陌生.现在跟着辉哥学习项目技术,打算好好的学习下这个工具的使用. 1 基础常识 1.1 基础讲解 star的作用是收藏,目的是方便以 ...

  6. Java流程控制---个人参考资料

    前言:我写博客的目的很简单,很单纯,把自己平时学的东西,放到博客上,空闲的时间,就可以看看自己曾经看到过得东西. Java流程控制语句:判断结构.选择结构.循环结构 一.判断结构 判断结构包括if 分 ...

  7. python XML梳理

    导入ElementTree模块 import xml.etree.ElementTree as ET 为了创建一个element实例,使用Element 构造函数或者SubElement()工厂函数. ...

  8. Hadoop生态圈-Flume的组件之自定义拦截器(interceptor)

    Hadoop生态圈-Flume的组件之自定义拦截器(interceptor) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客只是举例了一个自定义拦截器的方法,测试字节传输速 ...

  9. Spark记录-Scala集合

    Scala列表 Scala列表与数组非常相似,列表的所有元素都具有相同的类型,但有两个重要的区别. 首先,列表是不可变的,列表的元素不能通过赋值来更改. 其次,列表表示一个链表,而数组是平的. 具有类 ...

  10. hdu 5385 The path

    http://acm.hdu.edu.cn/showproblem.php?pid=5385 题意: 给定一张n个点m条有向边的图,构造每条边的边权(边权为正整数),令d(x)表示1到x的最短路,使得 ...