zoukankan      html  css  js  c++  java
  • .NET Core中合并Expression<Func<T,bool>>的正确姿势

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

    public static class ExpressionBuilder
    {
        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }
    
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.And);
        }
        
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.Or);
        }
    }

    迁移至 .NET Core 之后,Entity Framework Core 生成了不正确的 SQL 语句:

    WHERE (CASE
            WHEN ([q0].[IsActive] = 1) AND ([q.questionUser0].[IsActive] = 1)
            THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
        END & CASE
            WHEN [q0].[DealFlag] = 0
            THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
        END) AND (([q0].[Flags] & @__flags_0) = @__flags_1)

    在 Server Server 中执行时会出现如下的错误:

    在应使用条件的上下文(在 'AND' 附近)中指定了非布尔类型的表达式

    后来参考 Combining two expressions (Expression<Func<T, bool>>),通过下面的代码解决了问题:

    public static class ExpressionBuilder
    {
        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);
        }
    
        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);
        }
    
        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[0], parameter);
            var left = leftVisitor.Visit(expr1.Body);
    
            var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], 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);
            }
        }
    
    }
  • 相关阅读:
    cpp学习
    7-2 求逆序对数目 (20分) 归并排序 O(nlogn)
    Egret 滚动背景图的实现
    Egret-我的疑问:Scroller如何禁止水平或垂直方向滚动
    Egret-我的探索:exml自定义组件中通过ID获取子组件实例
    Egret-我的疑问:自定义组件加载skin的操作
    Egret事件冒泡的应用
    Egret点击穿透(使遮盖可点击组件的其他组件禁止点击)
    Egret wing 4.1.6项目目录结构
    Egret分步加载资源改写loading界面
  • 原文地址:https://www.cnblogs.com/dudu/p/6236378.html
Copyright © 2011-2022 走看看