zoukankan      html  css  js  c++  java
  • C# Expression 树转化为SQL语句(一)

    https://www.cnblogs.com/linxingxunyan/p/6245396.html

     sql有有四中基本语句,分别是增删改查,在建立model后如何生成这四中sql语句,降低开发时间。

       我们先模拟出一张学生表:

    复制代码
     public class Student
            {
                public int id { get; set; }
                public string name { get; set; }
                public int math { get; set; } //数学成绩
                public DateTime createTime { get; set; }
            }
    复制代码

         首先我们来看看增加,也就是插入语句。插入语句语法比较固定变化少通过泛型和反射可以直接生成。string类型和DateTime类型需要加单引号,其他类型不需要加。

      

    复制代码
    public static void Main(string[] args)
            {
                Student stu = new Student
                {
                    id = 1,
                    name = "张三",
                    matn = 59,
                    createTime = DateTime.Now
    
                };
                string sql = CreateInsertSql(stu);
                Console.WriteLine(sql);
                Console.ReadLine();
            }
            public static string CreateInsertSql<T>(T model)
            {
                string sql = "Insert into {0}({1}) Values({2})";
                string table = string.Empty;            //表名
                List<string> member = new List<string>(); //全部列名
                List<string> member_value = new List<string>(); //全部的值
                Type type = typeof(T);
                table = type.Name;
                foreach (PropertyInfo item in type.GetProperties())
                {
                    string name = item.Name;
                    member.Add(name);
                    object vaule = item.GetValue(model);
                    string v_str = string.Empty;
                    if (vaule is string)
                    {
                        v_str = string.Format("'{0}'", vaule.ToString());
                    }
                    else if (vaule is DateTime)
                    {
                        DateTime time = (DateTime)vaule;
                        v_str = string.Format("'{0}'", time.ToString("yyyy-MM-dd HH:mm:ss"));
                    }
                    else
                    {
                        v_str = vaule.ToString();
                    }
                    member_value.Add(v_str);
                }
                sql = string.Format(sql, table, string.Join(",", member), string.Join(",", member_value));
                return sql;
            }
    复制代码

    调试结果为:

      接下来我们来看看其他三种简单sql 删,改,查。简单的分析一下:

          删除:前面固定(delete from ) + 表名 + where条件

      修改:前面固定(update) +表名 +set + 修改内容+ where条件

      查找(根据model 我们默认查找全部字段): 前面固定(select * from ) + 表名 +where 条件

      从上面可以看出来我们需要3中参数(表名,修改内容,where条件)表名非常简单,可以把类名作为表名,反射一个就可以得到,接下来就是修改内容和where条件,修改内容比较简单格式为 set  a=a_value,b=b_value .........,where 条件较为复杂。

      用Expression 表达式树是受EntityFrame的启发,有些不了解的可以看看EF的一些函数的定义。

      现在就开始使用Expression表达式树来生产这2种sql语句。

      Expression表达式树有一个基类是Expression,然后有非常都的类继承这个类,我们想获取继承类的名称和命名空间的的时候可以用 :obj.GetType().Name 和obj.getType().Namespace来获取,这样便于调试。

      1. update中的修改内容。假设我们要对学生的分数进行修改(改成60,让人及格),还有姓名(就是凑个字段),其他的数据不修改。

      参数类型为: Expression<Func<Student, Student>> la = n => new Student { name = "李四", matn = 60 }; 我们要生成的sql为 name='李四',math=60,为什么类型是这个可以去看看EF扩展的内容。

      la类型是LambdaExpression,我们要解析的事la.Body 其类型为MemberInitExpression

    复制代码
     1   public static void Main(string[] args)
     2         {
     3             Expression<Func<Student, Student>> la = n => new Student { name = "李四", matn = 60 };
     4             Console.WriteLine(GetExpressStr((MemberInitExpression)(la.Body)));
     5             Console.ReadLine();
     6         }
     7         public static string GetExpressStr(MemberInitExpression exp)
     8         {
     9             string result = string.Empty;
    10             List<string> member = new List<string>();
    11             foreach (MemberAssignment item in exp.Bindings)
    12             {
    13                 string update = item.Member.Name + "=" + GetConstantStr((ConstantExpression)item.Expression);
    14                 member.Add(update);
    15             }
    16             result = string.Join(",", member);
    17             return result;
    18         }
    19         public static string GetConstantStr(ConstantExpression exp)
    20         {
    21             object vaule = exp.Value;
    22             string v_str = string.Empty;
    23             if (vaule is string)
    24             {
    25                 v_str = string.Format("'{0}'", vaule.ToString());
    26             }
    27             else if (vaule is DateTime)
    28             {
    29                 DateTime time = (DateTime)vaule;
    30                 v_str = string.Format("'{0}'", time.ToString("yyyy-MM-dd HH:mm:ss"));
    31             }
    32             else
    33             {
    34                 v_str = vaule.ToString();
    35             }
    36             return v_str;
    37         }
    复制代码

    调试结果:

      2.where条件

      where条件是最麻烦的地方。之前的只有等于号,而where却有大于,小于,且或等等符号,不过Exresion基类中提供了NodeType 类型为ExpressionType,我们可以获取到对应的运算符。参数类型为

      Expression<Func<Student,bool>>   简单理解where条件是每条数据符合不符合,所以返回值为bool
    复制代码
      1 public static void Main(string[] args)
      2         {
      3             Expression<Func<Student,bool>> la =( n=>n.id > 1 && n.id <100 &&n.name !="张三" && n.matn >=60 && n.id != 50 && n.createTime != null);
      4             Console.WriteLine(DealExpress(la));
      5             Console.ReadLine();
      6         }
      7         public static string DealExpress(Expression exp)
      8         {
      9             if (exp is LambdaExpression )
     10             {
     11                 LambdaExpression l_exp = exp as LambdaExpression;
     12                 return   DealExpress(l_exp.Body);
     13             }
     14             if (exp is BinaryExpression)
     15             {
     16                 return DealBinaryExpression(exp as BinaryExpression);
     17             }
     18             if (exp is MemberExpression)
     19             {
     20                 return DealMemberExpression(exp as MemberExpression);
     21             }
     22             if (exp is ConstantExpression)
     23             {
     24                 return DealConstantExpression(exp as ConstantExpression);
     25             }
     26             if (exp is UnaryExpression)
     27             {
     28                 return DealUnaryExpression(exp as UnaryExpression);
     29             }
     30             return "";
     31         }
     32         public static string DealUnaryExpression(UnaryExpression exp)
     33         {
     34             return DealExpress(exp.Operand);
     35         }
     36         public static string DealConstantExpression(ConstantExpression exp)
     37         {
     38             object vaule = exp.Value;
     39             string v_str = string.Empty;
     40             if (vaule == null)
     41             {
     42                 return "NULL";
     43             }
     44             if (vaule is string)
     45             {
     46                 v_str = string.Format("'{0}'", vaule.ToString());
     47             }
     48             else if (vaule is DateTime)
     49             {
     50                 DateTime time = (DateTime)vaule;
     51                 v_str = string.Format("'{0}'", time.ToString("yyyy-MM-dd HH:mm:ss"));
     52             }
     53             else
     54             {
     55                 v_str = vaule.ToString();
     56             }
     57             return v_str;
     58         }
     59         public static string DealBinaryExpression(BinaryExpression exp)
     60         {
     61 
     62             string left = DealExpress(exp.Left);
     63             string oper = GetOperStr(exp.NodeType);
     64             string right = DealExpress(exp.Right);
     65             if (right == "NULL")
     66             {
     67                 if (oper == "=")
     68                 {
     69                     oper = " is ";
     70                 }
     71                 else
     72                 {
     73                     oper = " is not ";
     74                 }
     75             }
     76             return left + oper + right;
     77         }
     78         public static string DealMemberExpression(MemberExpression exp)
     79         {
     80              return exp.Member.Name;
     81         }
     82         public static string GetOperStr(ExpressionType e_type)
     83         {
     84             switch (e_type)
     85             {
     86                 case ExpressionType.OrElse: return " OR ";
     87                 case ExpressionType.Or: return "|";
     88                 case ExpressionType.AndAlso: return " AND ";
     89                 case ExpressionType.And: return "&";
     90                 case ExpressionType.GreaterThan: return ">";
     91                 case ExpressionType.GreaterThanOrEqual: return ">=";
     92                 case ExpressionType.LessThan: return "<";
     93                 case ExpressionType.LessThanOrEqual: return "<=";
     94                 case ExpressionType.NotEqual: return "<>";
     95                 case ExpressionType.Add: return "+";
     96                 case ExpressionType.Subtract: return "-";
     97                 case ExpressionType.Multiply: return "*";
     98                 case ExpressionType.Divide: return "/";
     99                 case ExpressionType.Modulo: return "%";
    100                 case ExpressionType.Equal: return "=";
    101             }
    102             return "";
    103         }
    复制代码

    调试结果:

    这些代码中一些漏洞,仅供大家参考学习,这些代码目前不能接受参数,如n=>n.id==m(int m=1),下一篇将会对Expression表达式树的参数进行解析,欢迎大家指正。

    更新2019-11-21

    解决 bool 转数据库 bit 类型

    复制代码
      1   public static void Main(string[] args)
      2         {
      3             Expression<Func<Student, bool>> la = (n =>
      4                                                         n.id > 1
      5                                                         && n.id < 100 && n.name != "张三"
      6                                                         && n.math >= 60 && n.id != 50
      7                                                         && n.createTime != null
      8                                                         && n.delete
      9                                                         && n.IsDel == true
     10                                                         && !n.isAdmin
     11                                                         && 1 + 2 == 3
     12                                                         && 1 == 2);
     13 
     14             Expression<Func<Student, bool>> la2 = n=> 1+2==3;
     15 
     16             Console.WriteLine(DealExpress(la));
     17             Console.ReadLine();
     18         }
     19         public static string DealExpress(Expression exp)
     20         {
     21             if (exp is LambdaExpression)
     22             {
     23                 LambdaExpression l_exp = exp as LambdaExpression;
     24                 return DealBoolExp(l_exp.Body);
     25             }
     26             if (exp is BinaryExpression)
     27             {
     28                 return DealBinaryExpression(exp as BinaryExpression);
     29             }
     30             if (exp is MemberExpression)
     31             {
     32                 return DealMemberExpression(exp as MemberExpression);
     33             }
     34             if (exp is ConstantExpression)
     35             {
     36                 return DealConstantExpression(exp as ConstantExpression);
     37             }
     38             if (exp is UnaryExpression)
     39             {
     40                 return DealUnaryExpression(exp as UnaryExpression);
     41             }
     42             return "";
     43         }
     44         public static string DealBoolExp(Expression exp)
     45         {
     46             if (exp == null)
     47             {
     48                 var t = 1;
     49             }
     50             // 关于bool类型特殊处理
     51             if (exp is BinaryExpression) 
     52             {
     53                 return DealExpress(exp);
     54             }
     55             if (exp is MemberExpression) // n.isDelete 
     56             {
     57                 return DealMemberExpression(exp as MemberExpression) + "=1";
     58             }
     59             if (exp is UnaryExpression) //!n.isDelete
     60             {
     61                 return DealUnaryExpression(exp as UnaryExpression) + "<>1";
     62             }
     63             if (exp is ConstantExpression) //
     64             {
     65                 var str  = DealConstantExpression(exp as ConstantExpression);
     66                 return str == "1" ? "1==1" : "1!=1";
     67             }
     68             return "";
     69         }
     70 
     71 
     72         public static string DealUnaryExpression(UnaryExpression exp)
     73         {
     74             return DealExpress(exp.Operand);
     75         }
     76         public static string DealConstantExpression(ConstantExpression exp)
     77         {
     78             object vaule = exp.Value;
     79             string v_str = string.Empty;
     80             if (vaule == null)
     81             {
     82                 return "NULL";
     83             }
     84             if (vaule is string)
     85             {
     86                 v_str = string.Format("'{0}'", vaule.ToString());
     87             }
     88             else if (vaule is DateTime)
     89             {
     90                 DateTime time = (DateTime)vaule;
     91                 v_str = string.Format("'{0}'", time.ToString("yyyy-MM-dd HH:mm:ss"));
     92             }
     93             else if (vaule is Boolean)
     94             {
     95                 Boolean data = Convert.ToBoolean(vaule);
     96                 v_str = data? "1" : "0";
     97             }
     98             else
     99             {
    100                 v_str = vaule.ToString();
    101             }
    102             return v_str;
    103         }
    104         public static string DealBinaryExpression(BinaryExpression exp)
    105         {
    106 
    107             switch (exp.NodeType)
    108             {
    109                 case ExpressionType.OrElse:
    110                 case ExpressionType.AndAlso:
    111                     {
    112                         string left = DealBoolExp(exp.Left);
    113                         string oper = GetOperStr(exp.NodeType);
    114                         string right = DealBoolExp(exp.Right);
    115                         return left + oper + right;
    116 
    117                     }
    118                     
    119                 default:
    120                     {
    121                         string left = DealExpress(exp.Left);
    122                         string oper = GetOperStr(exp.NodeType);
    123                         string right = DealExpress(exp.Right);
    124                         if (right == "NULL")
    125                         {
    126                             if (oper == "=")
    127                             {
    128                                 oper = " is ";
    129                             }
    130                             else
    131                             {
    132                                 oper = " is not ";
    133                             }
    134                         }
    135                         return left + oper + right;
    136                     }
    137 
    138 
    139             }
    140 
    141           
    142         }
    143         public static string DealMemberExpression(MemberExpression exp)
    144         {
    145             var name = exp.Member.Name;
    146             if (name == "delete")
    147             {
    148                 var t = name;
    149             }
    150             return exp.Member.Name;
    151         }
    152         public static string GetOperStr(ExpressionType e_type)
    153         {
    154             switch (e_type)
    155             {
    156                 case ExpressionType.OrElse: return " OR ";
    157                 case ExpressionType.Or: return "|";
    158                 case ExpressionType.AndAlso: return " AND ";
    159                 case ExpressionType.And: return "&";
    160                 case ExpressionType.GreaterThan: return ">";
    161                 case ExpressionType.GreaterThanOrEqual: return ">=";
    162                 case ExpressionType.LessThan: return "<";
    163                 case ExpressionType.LessThanOrEqual: return "<=";
    164                 case ExpressionType.NotEqual: return "<>";
    165                 case ExpressionType.Add: return "+";
    166                 case ExpressionType.Subtract: return "-";
    167                 case ExpressionType.Multiply: return "*";
    168                 case ExpressionType.Divide: return "/";
    169                 case ExpressionType.Modulo: return "%";
    170                 case ExpressionType.Equal: return "=";
    171                
    172             }
    173             return "";
    174         }
    复制代码

    简单来讲 1。表达式整体 必须是 BinaryExpression 这个类型       2. 如果符号是 OR   或And    那么左右2边也必须是 BinaryExpression 

    代码有些取巧应该有些不足之处,仅供大家参考

  • 相关阅读:
    周末毒鸡汤时间
    MySQL 8.0发布,你熟悉又陌生的Hash Join?
    你可能需要的Kafka面试题与答案整理
    流程控制结构
    视图
    事务
    常用约束
    sql99语法的连接查询
    数据类型
    数据操作语句(DML)
  • 原文地址:https://www.cnblogs.com/chinasoft/p/15522411.html
Copyright © 2011-2022 走看看