C# Expression 樹轉化為SQL語句(一)


   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 

代碼有些取巧應該有些不足之處,僅供大家參考

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM