前面的文章封装了查询条件 自己去组装条件,但是对 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>> 查询条件遇到的问题的更多相关文章

  1. EF Core 封装方法Expression<Func<TObject, bool>>与Func<TObject, bool>区别

    unc<TObject, bool>是委托(delegate) Expression<Func<TObject, bool>>是表达式 Expression编译后就 ...

  2. lambda表达式Expression<Func<Person, bool>> 、Func<Person, bool>区别

    前言: 自己通过lambda表达式的封装,将对应的表达式转成字符串的过程中,对lambda表达式有了新的认识 原因: 很多开发者对lambda表达式Expression<Func<Pers ...

  3. Expression<Func<TObject, bool>>与Func<TObject, bool>的区别

    Func<TObject, bool>是委托(delegate) Expression<Func<TObject, bool>>是表达式 Expression编译后 ...

  4. Expression<Func<T, bool>>与Func<T, bool>的区别

    转自:http://www.cnblogs.com/wow-xc/articles/4952233.html Func<TObject, bool>是委托(delegate) Expres ...

  5. .NET Core中合并Expression<Func<T,bool>>的正确姿势

    这是在昨天的 .NET Core 迁移中遇到的问题,之前在 .NET Framework 中是这样合并 Expression<Func<T,bool>> 的: public s ...

  6. 表达式拼接Expression<Func<IEntityMapper, bool>> predicate

    /// <summary> /// 重写以筛选出当前上下文的实体映射信息 /// </summary> protected override IEnumerable<IE ...

  7. Expression<Func<T, bool>>

    public static Expression<Func<T, bool>> True<T>() { return f => true; } public ...

  8. 拉姆达表达式 追加 条件判断 Expression<Func<T, bool>>

    public static class PredicateBuilder { /// <summary> /// 机关函数应用True时:单个AND有效,多个AND有效:单个OR无效,多个 ...

  9. Entity Framework 动态构造Lambda表达式Expression<Func<T, bool>>

    using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...

随机推荐

  1. String类的一些细节

    先看一段代码: public static void main(String[] args) {        String a = "a"+"b"+1;   ...

  2. sqlbulkcopy 批量更新 数据库

    转载: http://blog.csdn.net/wangzh300/article/details/7382506 private static void DataTableToSQLServer( ...

  3. Tomcat源码解析-整体流程介绍

    一.架构 下面谈谈我对Tomcat架构的理解 总体架构: 1.面向组件架构 2.基于JMX 3.事件侦听 1)面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成 ...

  4. hdu 6301 Distinct Values (2018 Multi-University Training Contest 1 1004)

    Distinct Values Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  5. 51nod 1494 选举拉票 (线段树+扫描线)

    1494 选举拉票  题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 现在你要竞选一个县的县长.你去对每一个选民进 ...

  6. 鸟哥的Linux私房菜——第十五章:正规表示法

    视频链接 B站:http://www.bilibili.com/video/av10364761/ 目录如下 1. 前言:2. 基础正规表示法:2.1 以 grep 撷取字符串 (grep -iv   ...

  7. JDBC编程示例

    package com.lovo.test; import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLE ...

  8. J2EE完全手册(二)

    1.2 客户端 (Web客户端,应用程序客户端) 1.2.1 Web客户端: 一般简单讲,就是显示由在Web层的web组件中生成的包含Html 及 XML标记语言的动态Web页面(.jsp[.do]) ...

  9. Sql语句 表中相同的记录(某个字段)只显示一条,按照时间排序显示最大或最小

    原始表数据:

  10. Ubuntu14.04搭建Android O编译环境

    一.搭建环境 官方参考文档: 1.代号.标签和版本号 2.Factory Images 3.Driver Binaries 4.工具链  软硬件版本: 1.系统平台:I5-8500T+8G+1T,Ub ...