zoukankan      html  css  js  c++  java
  • 使用EF构建企业级应用(三)

    使用EF构建企业级应用(三)

    2012-04-10 14:42 by 谢中涞, 880 visits, 收藏编辑

    在前两篇文章中,我们已经实现了基于EF的数据库基本操作基类的构建,以及简单的介绍了如何方便的动态构建排序表达式,在第二篇文章结尾,我们遗漏下来了一个问题:如何方便的构建查询参数(即类似于这样的Expression<TEntity, bool> expression查询表达式)

    在往常的经验中,我们知道在和数据库交互的过程中,查询可能是最复杂的,做过数据持久化封装的同学们可能对这个认识尤为突出,其他原因我们就不细说了, 如何丰富的,易用的构建查询条件这个就有点让人迷惑.

    我们来分析一个常见的查询条件(a>4 and b<3)Or(d>5 and c in(3,4,5)),

    1. 设定:var exp1=a>4 and b<3;  var exp2=d>5 and c in(3,4,5),则上述条件可以表示为 var exp=exp1 or exp2;
    2. 进一步分解exp1:var exp1_1=a>4; var exp1_2=b<3; 则exp1=exp1_1 and var exp_2
    3. 进一步分解exp2:var exp2_1=d>5; var exp2_2=c in (3,4,5); 则exp2=exp2_1 and exp2_2

    有了上面的分解,我们发现其实构建这个查询条件非常符合我们常见的递归算法.下面我们尝试一下用递归的思想来实现这个.我们先大致的画个UML草图image

    为了不和系统下面的Expression 命名混淆,我们这里采用EFExpression作为条件表达式基类名称,

    1. EFExpression<T> 为一个抽象基类,里面主要有一个返回类型为 Expression<Func<T,bool>> GetExpression()的一个抽象方法,其具体实现,我们放在了每一个具体的Expression中去定义.
    2. EmptyEFExpression<T> 表示一个空的查询表达式
    3. BinaryEFExpression<T> 表示一个基于二元条件的查询表达式,如大于,小于,等于 ……
    4. LikeEFExpression<T> 表示一个用于创建”类似于”条件的查询表达式
    5. LogicEFExpression<T> 表示一个逻辑运算的查询表达式,如and or
    6. ….可能还会有其他子类

    1.首先我们试着来编写一下抽象基类EFExpression<T>的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    /// <summary>
    /// 查询表达式基类
    /// </summary>
    public abstract class EFExpression<T> where T : class
    {
     
        /// <summary>
        /// 获取查询表达式
        /// </summary>
        /// <returns></returns>
        public virtual Expression<Func<T, bool>> GetExpression()
        {
            if (Expression != null)
            {
                var candidateExp = Expression.Parameter(typeof(T), "x");
                var exp = Expression.Lambda<Func<T, bool>>(Expression, candidateExp);
                return exp;
            }
            else
            {
                return null;
            }
        }
     
        /// <summary>
        /// 查询条件对应表达式
        /// </summary>
        protected Expression _Expression { get; set; }
     
        /// <summary>
        /// 参数表达式
        /// </summary>
        public ParameterExpression[] Parameters { get; set; }
     
        /// <summary>
        /// 获取对应的表达式
        /// </summary>
        internal abstract Expression Expression { get; }
     
        /// <summary>
        /// 获取表达式主题
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="P"></typeparam>
        /// <param name="old"></param>
        /// <param name="property"></param>
        /// <returns></returns>
        protected static Expression GetMemberExpression<T, P>(EFExpression<T> old, Expression<Func<T, P>> property)
            where T : class
        {
            if (old.Parameters == null || old.Parameters.Length == 0)
            {
                old.Parameters = property.Parameters.ToArray();
                return property.Body;
            }
     
            ParameterExpressionVisitor visitor = new ParameterExpressionVisitor(old.Parameters[0]);
     
            Expression memberExpr = visitor.ChangeParameter(property.Body);
     
            return memberExpr;
        }
     
        /// <summary>
        /// 获取一个空的表达式
        /// </summary>
        /// <returns></returns>
        public Expression<Func<T, bool>> GetEmptyExpression()
        {
            return (Expression<Func<T, bool>>)(f => true);
        }
     
        /// <summary>
        /// 两个条件进行And运算
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public static EFExpression<T> operator &(EFExpression<T> left, EFExpression<T> right)
        {
            return new LogicEFExpression<T>(left, ELogicType.And, right);
        }
        /// <summary>
        /// 两个条件进行Or运行
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public static EFExpression<T> operator |(EFExpression<T> left, EFExpression<T> right)
        {
            return new LogicEFExpression<T>(left, ELogicType.Or, right);
        }
    }

    2. 接着我们来看一下如何实现这个BinaryEFExpression<T>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    /// <summary>
        /// 二元运算查询条件
        /// </summary>
        /// <typeparam name="T">查询条件实体类型</typeparam>
        /// <typeparam name="TVal">需要比较的属性类型</typeparam>
        internal class BinanryEFExpression<T, TVal> : EFExpression<T>
            where T : class
            where TVal : IComparable
        {
            /// <summary>
            /// 定义条件的实体属性
            /// </summary>
            private Expression<Func<T, TVal>> property;
     
            /// <summary>
            /// 比较的值
            /// </summary>
            private TVal val;
     
            /// <summary>
            /// 二元运算符
            /// </summary>
            private EBinaryType binaryType;
     
            /// <summary>
            /// 实例化新的二元查询表达式
            /// </summary>
            /// <param name="property">定义条件的实体属性</param>
            /// <param name="binaryType">二元运算符</param>
            /// <param name="val">比较的值</param>
            public BinanryEFExpression(Expression<Func<T, TVal>> property, EBinaryType binaryType, TVal val)
            {
                if (property == null)
                    throw new ArgumentNullException("property");
                //if (val == null && binaryType != EBinaryType.Like)
                //    throw new ArgumentNullException("val");
                this.property = property;
                this.val = val;
                this.binaryType = binaryType;
            }
     
            internal override Expression Expression
            {
                get
                {
                    if (_Expression == null)
                    {
                        var propertyBody = GetMemberExpression(this, property);
     
                        Type type = typeof(TVal);
                        Expression compareVal = Expression.Constant(val);
                        //如果是Nullable类型,则把value转化成Nullable类型
                        if (type.IsNullableType())
                        {
                            compareVal = Expression.Convert(compareVal, type);
                        }
                        Expression tempExp = null;
                        switch (binaryType)
                        {
                            case EBinaryType.Equal:
                                tempExp = Expression.Equal(propertyBody, compareVal);
                                break;
                            case EBinaryType.GreaterThan:
                                tempExp = Expression.GreaterThan(propertyBody, compareVal);
                                break;
                            case EBinaryType.GreaterThanOrEqual:
                                tempExp = Expression.GreaterThanOrEqual(propertyBody, compareVal);
                                break;
                            case EBinaryType.LessThan:
                                tempExp = Expression.LessThan(propertyBody, compareVal);
                                break;
                            case EBinaryType.LessThanOrEqual:
                                tempExp = Expression.LessThanOrEqual(propertyBody, compareVal);
                                break;
                            case EBinaryType.NotEqual:
                                tempExp = Expression.NotEqual(propertyBody, compareVal);
                                break;
                            default:
                                break;
                        }
                        _Expression = tempExp;
                    }
                    return _Expression;
                }
            }
        }

    3.我们在来看一下关于表达式逻辑运算的LogicEFExpression<T> 类又是如何实现的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    /// <summary>
       /// 带有逻辑运算的查询表达式
       /// </summary>
       /// <typeparam name="T"></typeparam>
       public class LogicEFExpression<T> : EFExpression<T> where T : class
       {
           private EFExpression<T> left;
           private EFExpression<T> right;
           private ELogicType logicType;
     
           /// <summary>
           /// 实例化新的逻辑运算查询表达式
           /// </summary>
           /// <param name="left"></param>
           /// <param name="logicType">逻辑运算类型</param>
           /// <param name="right"></param>
           public LogicEFExpression(EFExpression<T> left, ELogicType logicType, EFExpression<T> right)
           {
               if (left == null || right == null)
                   throw new ArgumentNullException("left 和 right 不能同时为空");
               this.left = left;
               this.right = right;
               this.logicType = logicType;
           }
     
           public override Expression<Func<T, bool>> GetExpression()
           {
               if (left == null)
                   return right.GetExpression();
               else if (right == null)
                   return left.GetExpression();
               else
               {
                   //判断进行运算的两个条件是否为空
                   if (left is EmptyEFExpression<T> && right is EmptyEFExpression<T>)
                       return left.GetExpression();
                   else if (left is EmptyEFExpression<T>)
                       return right.GetExpression();
                   else if (right is EmptyEFExpression<T>)
                       return left.GetExpression();
     
                   var leftExp = left.GetExpression();
                   var rightExp = right.GetExpression();
                   Expression<Func<T, bool>> exp = null;
     
                   if (leftExp == null && rightExp == null)
                       return new EmptyEFExpression<T>().GetExpression();
                   else
                   {
                       if (leftExp == null)
                           return rightExp;
                       else if (rightExp == null)
                           return leftExp;
                       else
                       {
                           switch (logicType)
                           {
                               case ELogicType.And:
                                   exp = leftExp.And(rightExp);
                                   break;
                               case ELogicType.Or:
                                   exp = leftExp.Or(rightExp);
                                   break;
                               default:
                                   break;
                           }
                       }
                   }
                   return exp;
               }
           }
     
           internal override Expression Expression
           {
               get
               {
                   return null;
               }
           }
       }
    
    


     

    4.为了使用方便,我们在基类中再添加个静态方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /// <summary>
           /// 构建一个二元查询表达式
           /// </summary>
           /// <typeparam name="TVal">比较值的类型</typeparam>
           /// <param name="property">定义条件的实体属性</param>
           /// <param name="binaryType">运算符类型</param>
           /// <param name="val">比较的值</param>
           /// <returns></returns>
           public static EFExpression<T> CreateBinaryExpression<TVal>(Expression<Func<T, TVal>> property,
               EBinaryType binaryType, TVal val) where TVal : IComparable
           {
               return new BinanryEFExpression<T, TVal>(property, binaryType, val);
           }

    5.有了上面的实现,我们来测试下我们的想法.为了让我们更容易理解,我们假设在一个订单管理环境中,有如下一个需求:请查询满足以下任意一个条件中的订单记录

    1. 订单状态还未送货且金额>50W的
    2. 订单状态为送货中,且客户地址在深圳片区的

    为了便于理解,我们在这里先定义两个实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /// <summary>
    /// 订单主表
    /// </summary>
    public class OrderMain
    {
        public Guid Id { get; set; }
        public string Code { get; set; }
        public DateTime BillDate { get; set; }
        public Guid CustomerId { get; set; }
        public virtual Customer Customer { get; set; }
        public decimal TotalAmount { get; set; }
        public int Status { get; set; }
    }
    /// <summary>
    /// 客户信息
    /// </summary>
    public class Customer
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string Area { get; set; }
    }

    那么我们这里使用的查询条件可能就会写成如下形式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var exp=EFExpression<OrderMain>.CreateBinaryExpression(o=>o.Status,EBinaryType.Equal,0);   //还没有送货
     
    exp&=EFExpression<OrderMain>.CreateBinaryExpression(o=>o.TotalAmount ,EBinaryType.LessThan,500000);  //小于50W
     
    var exp2=EFExpression<OrderMain>.CreateBinaryExpression(o=>o.Status,EBinaryType.Equal,1);   //送货中
     
    exp2&=EFExpression<OrderMain>.CreateBinaryExpression(o=>o.Customer.Area,EBinaryType.Equal,”0755”);  //地址在深圳片区
     
    exp|=exp2;
     
    var queryExpression=exp.GetExpression();

    测试通过.大笑,至于其他的子类在此就不一一列举了,当然我们可以通过扩展一些写法使之更容易使用,比如

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    /// <summary>
           /// 在当前条件基础上,构建一个like条件,并且和当前条件产生And运算
           /// </summary>
           /// <param name="property"></param>
           /// <param name="val"></param>
           /// <returns></returns>
           public static EFExpression<T> AndLike<T>(this EFExpression<T> old, Expression<Func<T, string>> property, string val) where T : class
           {
               var temp = new LikeEFExpression<T>(property, val);
               if (old == null)
                   return temp;
               else
                   return new LogicEFExpression<T>(old, ELogicType.And, temp);
           }
     
           /// <summary>
           /// 在当前条件基础上,构建一个等于条件,并且和当前条件产生And运算
           /// </summary>
           /// <typeparam name="TVal"></typeparam>
           /// <param name="old"></param>
           /// <param name="property"></param>
           /// <param name="val"></param>
           /// <returns></returns>
           public static EFExpression<T> AndEqual<T, TVal>(this EFExpression<T> old, Expression<Func<T, TVal>> property, TVal val)
               where TVal : IComparable
               where T : class
           {
               var temp = new BinanryEFExpression<T, TVal>(property, EBinaryType.Equal, val);
               if (old == null)
                   return temp;
               else
                   return new LogicEFExpression<T>(old, ELogicType.And, temp);
           }
     
           /// <summary>
           /// 在当前条件基础上,构建一个大于条件,并且和当前条件产生And运算
           /// </summary>
           /// <typeparam name="TVal"></typeparam>
           /// <param name="old"></param>
           /// <param name="property"></param>
           /// <param name="val"></param>
           /// <returns></returns>
           public static EFExpression<T> AndGreaterThan<T, TVal>(this EFExpression<T> old, Expression<Func<T, TVal>> property, TVal val)
               where TVal : IComparable
               where T : class
           {
               var temp = new BinanryEFExpression<T, TVal>(property, EBinaryType.GreaterThan, val);
               if (old == null)
                   return temp;
               else
                   return new LogicEFExpression<T>(old, ELogicType.And, temp);
           }

    那么我们在使用的时候就可以方便的写成下面这种形式

    var exp=EFExpression<OrderMain>.Create().AndEqual(o=>o.Status,0).AndGreaterThan(o=>o.TotalAmount ,500000)…..

    在此不再赘述,有兴趣的朋友们可以自己去写出类似的东东,或问我要源码包...

    http://www.cnblogs.com/xie-zhonglai/archive/2012/04/10/2440569.html

  • 相关阅读:
    Rainmeter 雨滴桌面 主题分享
    行人检測之HOG特征(Histograms of Oriented Gradients)
    const和readonly差别
    ADB命令解析
    Java实现 蓝桥杯VIP 算法训练 接水问题
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2441782.html
Copyright © 2011-2022 走看看