.NetCore 扩展封装 Expression<Func<T, bool>> 查询条件遇到的问题
前面的文章封装了查询条件 自己去组装条件,但是对 And Or 这种组合支持很差,但是也不是不能支持,只是要写更多的代码看起来很臃肿
根据 Where(Expression<Func<T, bool>>) 我们直接来处理这个,在处理这个之前其实看了下
Expression这个对象的处理,本生里面是包含了 AndAlso 、 Or 的处理 先来看看这个会遇到什么问题?为什么不行?
比如:
Expression.AndAlso(first,second)
来一段之前的扩展
public static Expression AndExpression(this Expression expression, Expression right)
{
return Expression.AndAlso(expression, right); }
public static Expression OrExpression(this Expression expression, Expression right)
{
return Expression.Or(expression, right); }
public static Expression<Func<T,bool>> ToFilter<T>(this Expression expression)
{
return Expression.Lambda<Func<T, bool>>(expression, Expression.Parameter(typeof(T))); }
本质上没什么不同,最后连接都能拿到相关的表达式
Expression filter= Expression.Constant(true, typeof(bool));
if (!string.IsNullOrEmpty(username))
{
filter = filter.AndExpression(new UosoConditions {
Key = "UserName",
Operator = UosoOperatorEnum.Contains,
Value = username,
ValueType = "string"
}.Parser<IdentityUser>());
}
按照如上写法多写几个条件,2个查询条件,2个值,感觉没问题, 但是运行到Where的时候报错误 表到时Parameter参数的个数对应不上表达式参数的个数,参数丢失了?
参数的值跟随表达式,在组合的时候需要重新组合参数,如果直接组合表达式,参数不会发生变化所以需要处理下参数问题,对(Expression<Func<T, bool>>) 的扩展就迎刃而解了
正确的处理方式:
public static class ExpressionExtensions
{
/// <summary>
/// 添加And条件
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.AndAlso<T>(second, Expression.AndAlso);
}
/// <summary>
/// 添加Or条件
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> first,
Expression<Func<T, bool>> second)
{
return first.AndAlso<T>(second, Expression.OrElse);
}
/// <summary>
/// 合并表达式以及参数
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expr1"></param>
/// <param name="expr2"></param>
/// <param name="func"></param>
/// <returns></returns>
private static Expression<Func<T, bool>> AndAlso<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2,
Func<Expression, Expression, BinaryExpression> func)
{
var parameter = Expression.Parameter(typeof(T)); var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[], parameter);
var left = leftVisitor.Visit(expr1.Body); var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[], parameter);
var right = rightVisitor.Visit(expr2.Body); return Expression.Lambda<Func<T, bool>>(
func(left, right), parameter); } private class ReplaceExpressionVisitor
: ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue; public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
} public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue;
return base.Visit(node);
}
}
}
使用方法就简单多了
Expression<Func<IdentityUser, bool>> filter = u => true;
if (!string.IsNullOrEmpty(username))
{
filter = filter.And(c => c.UserName.Contains(username));
}
if (!string.IsNullOrEmpty(phone))
{
filter = filter.And(c => c.PhoneNumber.Contains(phone));
}
if (!string.IsNullOrEmpty(email))
{
filter = filter.And(c => c.Email.Contains(email));
}
这里值得注意的是 一定要重新赋值到 filter ,按理说扩展了Expression<Func<T, bool>> 也返回了 Expression<Func<T, bool>> 好像可以不用重新赋值,然而这里并不是这样
如果我们直接
filter.And(c => c.UserName.Contains(username));
这样添加 会发现之中都是第一个参数的条件 都是 true,这是为什么呢?
Expression<Func<IdentityUser, bool>> filter = u => true;
下面看下这段代码其实给之前出现错误的原因是一样的?
private static Expression<Func<T, bool>> AndAlso<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2,
Func<Expression, Expression, BinaryExpression> func)
{
var parameter = Expression.Parameter(typeof(T)); var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[], parameter);
var left = leftVisitor.Visit(expr1.Body); var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[], parameter);
var right = rightVisitor.Visit(expr2.Body); return Expression.Lambda<Func<T, bool>>(
func(left, right), parameter); }
var parameter = Expression.Parameter(typeof(T)); 是对 T 类中做的反射,本生合并两个带 T 的应该是没问题的,只是因为
与 Expression<Func<IdentityUser, bool>> filter = u => true; 组合后
Expression.Lambda<Func<T, bool>>(
func(left, right), parameter);
一直都是True,导致最后的条件都是返回 True 查询条件就无效了,所以需要重新引用赋值 filter
.NetCore 扩展封装 Expression<Func<T, bool>> 查询条件遇到的问题的更多相关文章
- EF Core 封装方法Expression<Func<TObject, bool>>与Func<TObject, bool>区别
unc<TObject, bool>是委托(delegate) Expression<Func<TObject, bool>>是表达式 Expression编译后就 ...
- lambda表达式Expression<Func<Person, bool>> 、Func<Person, bool>区别
前言: 自己通过lambda表达式的封装,将对应的表达式转成字符串的过程中,对lambda表达式有了新的认识 原因: 很多开发者对lambda表达式Expression<Func<Pers ...
- Expression<Func<TObject, bool>>与Func<TObject, bool>的区别
Func<TObject, bool>是委托(delegate) Expression<Func<TObject, bool>>是表达式 Expression编译后 ...
- Expression<Func<T, bool>>与Func<T, bool>的区别
转自:http://www.cnblogs.com/wow-xc/articles/4952233.html Func<TObject, bool>是委托(delegate) Expres ...
- .NET Core中合并Expression<Func<T,bool>>的正确姿势
这是在昨天的 .NET Core 迁移中遇到的问题,之前在 .NET Framework 中是这样合并 Expression<Func<T,bool>> 的: public s ...
- 表达式拼接Expression<Func<IEntityMapper, bool>> predicate
/// <summary> /// 重写以筛选出当前上下文的实体映射信息 /// </summary> protected override IEnumerable<IE ...
- Expression<Func<T, bool>>
public static Expression<Func<T, bool>> True<T>() { return f => true; } public ...
- 拉姆达表达式 追加 条件判断 Expression<Func<T, bool>>
public static class PredicateBuilder { /// <summary> /// 机关函数应用True时:单个AND有效,多个AND有效:单个OR无效,多个 ...
- Entity Framework 动态构造Lambda表达式Expression<Func<T, bool>>
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...
随机推荐
- C# 多线程之Thread类
使用System.Threading.Thread类可以创建和控制线程. 常用的构造函数有: // 摘要: // 初始化 System.Threading.Thread 类的新实例,指定允许对象在 ...
- 一本通1628X-factor Chain
1628:X-factor Chain 时间限制: 1000 ms 内存限制: 524288 KB [题目描述] 原题来自 POJ 3421 输入正整数 x,求 x 的大于 1 的因子 ...
- Good Bye 2018 没打记
场外选手赛时只口胡出了CD感觉非常惨.只看了E并且还没看到题面里的wiki我能咋办 C:f只与gcd(n,k)有关. D:考虑每种起始位置,对于跨越的两个排列,只有前一个排列的后缀单减时不产生贡献.答 ...
- 【BZOJ1019】[SHOI2008]汉诺塔(数论,搜索)
[BZOJ1019][SHOI2008]汉诺塔(数论,搜索) 题面 BZOJ 洛谷 题解 首先汉诺塔问题的递推式我们大力猜想一下一定会是形如\(f_i=kf_{i-1}+b\)的形式. 这个鬼玩意不好 ...
- 《剑指offer》— JavaScript(34)第一个只出现一次的字符
第一个只出现一次的字符 题目描述 在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置. *** 思路 新建一个对象,其中key用 ...
- 在windows上部署使用Redis出现问题的解决方法
下载Redis 在Redis的官网下载页上有各种各样的版本,我这次是在windows上部署的,要去GitHub上下载.目前的是2.8.12版的,直接解压,在\bin\release 目录下有个压缩包, ...
- 虚拟机中liunx安装教程
目标:在Linux服务器上部署Java开发的网站 工具 VirtualBox-4.3.8:下载后安装. linux系统镜像: Centos国内镜像文件下载地址: http://centos.ustc ...
- python的类的继承-接口继承-归一化设计
1.先在子类本身找,如果子类没有,会去父类找 class Dad: '这个是爸爸类' money=10#Dad类的数据属性 def __init__(self,name): print("爸 ...
- Linux 之 crontab 使用
定时任务 任务调度的crond常驻命令crond 是linux用来定期执行程序的命令.当安装完成操作系统之后,默认便会启动此任务调度命令.crond命令每分锺会定期检查是否有要执行的工作,如果有要执行 ...
- Git与GitHub学习笔记(二)提交的一些笔记
1.合并分支的使用一定要切换到master分支上去合并:git merge company2.切换分支的时候一定要提交干净本地分支的代码,才可以切换分支,否则提示错误信息: 3.这时候我们做的就是提交 ...