自己動手寫ORM(01):解析表達式樹生成Sql碎片

来源:http://www.cnblogs.com/lispring/archive/2016/03/26/5324348.html
-Advertisement-
Play Games

什麼是ORM框架: ORM即對象關係映射(Object Relational Mapping,簡稱ORM),是一種為瞭解決面向對象與關係資料庫存在的互不匹配的現象的技術。簡單的說,ORM是通過使用描述對象和資料庫之間映射的元數據,將程式中的對象自動持久化到關係資料庫中。 自己也用過很多ORM框架,比 ...


什麼是ORM框架:

    ORM即對象關係映射(Object Relational Mapping,簡稱ORM),是一種為瞭解決面向對象與關係資料庫存在的互不匹配的現象的技術。簡單的說,ORM是通過使用描述對象和資料庫之間映射的元數據,將程式中的對象自動持久化到關係資料庫中。

   自己也用過很多ORM框架,比如微軟的EF,Hibernate。輕量級一點的有Depper等等。這些框架說白了就是讓我們能像操作對象那樣去操作資料庫。

   鄙人是個比較懶的程式猿,總想這寫更少的代碼做更多的事情,最近不是很忙,於是我就試著寫寫自己的ORM框架。在此之前我用反射寫過ORM框架,總覺得性能比較低,在將查詢結果轉化成實體對象的時候,我沒用反射,這樣讓實體類變得有點重,這次的目標是把實體類變得簡單,並且不用反射。那麼廢話不多說,直接進入主題。

解析Expression Tree 轉生成Sql碎片:

  至於設麽是表達式樹,在此我就不做說明,園子里有很多文章,大家都可以去看看。

    在EF中,我們查詢數據時可能會用拉姆達表達式 Where(Func<T,ture> func)這個方法來篩選數據,例如,我們定義一個User實體類

    

1 public class User 
2     {
3         public Guid Id { get; set; }
4         public string LoginId { get; set; }
5         public string Name { get; set; }
6         public bool Enabled { get; set; }
7         public DateTime CreateTime { get; set; }
8     }

 

  現在我想查詢用戶Enabled為true 並且Name 中包含'lilei'的用戶,在EF中我們可能會這樣去寫:

XXX.Where(u => u.Name.Contains("lilei") && u.Enabled==true)

  那麼現在我想將Where方法中的那個泛型委托翻譯成Sql語句中的一部分應該怎麼做呢?下麵是我已經寫好的一個解析表達式的類,可能寫得不是很規範,大家儘量吐槽:

  1 using LC.Factory.Code;
  2 using LC.Factory.Entity;
  3 using LC.Factory.Resource;
  4 using System;
  5 using System.Collections.Generic;
  6 using System.Linq;
  7 using System.Linq.Expressions;
  8 using System.Reflection;
  9 using System.Text;
 10 using System.Text.RegularExpressions;
 11 
 12 
 13 namespace LC.Factory.Common
 14 {
 15     public class ExpressionAnalyzer
 16     {
 17         /// <summary>
 18         /// 表達式所有參數集合
 19         /// </summary>
 20         private Dictionary<string, object> _params;
 21         /// <summary>
 22         /// 命名參數別名
 23         /// </summary>
 24         private const string _argName = "TAB";
 25         /// <summary>
 26         /// 解析結果
 27         /// </summary>
 28         public AnalysisData ResultData { get; set; }
 29         public ExpressionAnalyzer()
 30         {
 31             ResultData = new AnalysisData();
 32             _params = new Dictionary<string, object>();
 33 
 34         }
 35         public ExpressionAnalyzer(LambdaExpression exp)
 36             : this()
 37         {
 38             if (exp != null)
 39             {
 40                 AppendParams(GetChildValue(exp.Body), _params);
 41                 foreach (var item in exp.Parameters)
 42                 {
 43                     AnalysisTables(item);
 44                 }
 45                 AnalysisExpression(exp.Body, true);
 46             }
 47         }
 48         /// <summary>
 49         /// 解析表達式
 50         /// </summary>
 51         /// <param name="exp"></param>
 52         /// <param name="isLeftChild"></param>
 53         private void AnalysisExpression(Expression exp, bool isLeftChild = true)
 54         {
 55             switch (exp.NodeType)
 56             {
 57                 case ExpressionType.AndAlso:
 58                     ResultData.StackList.Add("(");
 59                     AnalysisExpression(GetChildExpression(exp));
 60                     ResultData.StackList.Add(")");
 61                     ResultData.StackList.Add("AND");
 62                     ResultData.StackList.Add("(");
 63                     AnalysisExpression(GetChildExpression(exp, false), false);
 64                     ResultData.StackList.Add(")");
 65                     break;
 66                 case ExpressionType.OrElse:
 67                     ResultData.StackList.Add("(");
 68                     AnalysisExpression(GetChildExpression(exp));
 69                     ResultData.StackList.Add(")");
 70                     ResultData.StackList.Add("OR");
 71                     ResultData.StackList.Add("(");
 72                     AnalysisExpression(GetChildExpression(exp, false), false);
 73                     ResultData.StackList.Add(")");
 74                     break;
 75                 case ExpressionType.Equal:
 76                     AnalysisExpression(GetChildExpression(exp));
 77                     ResultData.StackList.Add("=");
 78                     AnalysisExpression(GetChildExpression(exp, false), false);
 79                     break;
 80                 case ExpressionType.NotEqual:
 81                     AnalysisExpression(GetChildExpression(exp));
 82                     ResultData.StackList.Add("!=");
 83                     AnalysisExpression(GetChildExpression(exp, false), false);
 84                     break;
 85                 case ExpressionType.GreaterThanOrEqual:
 86                     AnalysisExpression(GetChildExpression(exp));
 87                     ResultData.StackList.Add(">=");
 88                     AnalysisExpression(GetChildExpression(exp, false), false);
 89                     break;
 90                 case ExpressionType.GreaterThan:
 91                     AnalysisExpression(GetChildExpression(exp));
 92                     ResultData.StackList.Add(">");
 93                     AnalysisExpression(GetChildExpression(exp, false), false);
 94                     break;
 95                 case ExpressionType.LessThan:
 96                     AnalysisExpression(GetChildExpression(exp));
 97                     ResultData.StackList.Add("<");
 98                     AnalysisExpression(GetChildExpression(exp, false), false);
 99                     break;
100                 case ExpressionType.LessThanOrEqual:
101                     AnalysisExpression(GetChildExpression(exp));
102                     ResultData.StackList.Add("<=");
103                     AnalysisExpression(GetChildExpression(exp, false), false);
104                     break;
105                 case ExpressionType.Call:
106                     var imExp = exp as MethodCallExpression;
107                     AnalysisExpression(imExp.Object, true);
108                     ResultData.StackList.Add("LIKE");
109                     if (imExp.Arguments.Count > 0)
110                     {
111                         var arg0 = imExp.Arguments[0] as MemberExpression;
112                         ResultData.StackList.Add("'%'+");
113                         AnalysisExpression(imExp.Arguments[0], false);
114                         ResultData.StackList.Add("+'%'");
115                     }
116                     break;
117                 case ExpressionType.MemberAccess:
118                     if (isLeftChild)
119                     {
120                         AnalysisTables(exp);
121                         var mberExp = exp as MemberExpression;
122                         var parentName = GetExpressionName(mberExp.Expression);
123                         if (!string.IsNullOrEmpty(parentName))
124                         {
125                             ResultData.StackList.Add(string.Format("[{0}].{1}", parentName, GetExpressionName(exp)));
126                             break;
127                         }
128                         ResultData.StackList.Add(GetExpressionName(exp));
129                     }
130                     else
131                     {
132                         var paramName = GetParamName(exp);
133                         ResultData.ParamList.Add(paramName, _params[paramName]);
134                         ResultData.StackList.Add(paramName);
135                     }
136                     break;
137                 case ExpressionType.Constant:
138                     var constent = exp as ConstantExpression;
139                     if (constent.Value == null)
140                     {
141                         var op = ResultData.StackList.ElementAt(ResultData.StackList.Count - 1);
142                         ResultData.StackList.RemoveAt(ResultData.StackList.Count - 1);
143                         if (string.Equals(op, "="))
144                         {
145                             ResultData.StackList.Add("IS NULL");
146                         }
147                         else
148                         {
149                             ResultData.StackList.Add("IS NOT NULL");
150                         }
151                         break;
152                     }
153                     if (constent.Value.GetType() == typeof(String))
154                     {
155                         ResultData.StackList.Add(string.Format("'{0}'", constent.Value));
156                         break;
157                     }
158                     if (constent.Value.GetType() == typeof(bool))
159                     {
160                         if (ResultData.StackList.Count > 0)
161                         {
162                             var value = Convert.ToBoolean(constent.Value);
163                             ResultData.StackList.Add(string.Format("{0}", value ? "1" : "0"));
164                         }
165 
166                         break;
167                     }
168                     ResultData.StackList.Add(string.Format("{0}", constent.Value));
169                     break;
170                 case ExpressionType.Convert:
171                     var uExp = exp as UnaryExpression;
172                     AnalysisExpression(uExp.Operand, isLeftChild);
173                     break;
174                 case ExpressionType.New:
175                     var newExp = exp as NewExpression;
176                     //解析查詢欄位
177                     for (int i = 0; i < newExp.Arguments.Count; i++)
178                     {
179                         AnalysisExpression(newExp.Arguments[i]);
180                         ResultData.StackList.Add("AS");
181                         ResultData.StackList.Add(string.Format("'{0}'", newExp.Members[i].Name));
182                     }
183                     break;
184                 case ExpressionType.Parameter:
185                     throw new BusinessException(BusinessRes.SelectObjectMastBeAnNewObject);
186                 //AnalysisExpression(Expression.New(exp.Type));
187                 //break;
188                 default:
189                     break;
190             }
191 
192         }
193         /// <summary>
194         /// 獲取孩子節點
195         /// </summary>
196         /// <param name="exp"></param>
197         /// <param name="getLeft"></param>
198         /// <returns></returns>
199         private Expression GetChildExpression(Expression exp, bool getLeft = true)
200         {
201             var className = exp.GetType().Name;
202             switch (className)
203             {
204                 case "BinaryExpression":
205                 case "LogicalBinaryExpression":
206                     var bExp = exp as BinaryExpression;
207                     return getLeft ? bExp.Left : bExp.Right;
208                 case "PropertyExpression":
209                 case "FieldExpression":
210                     var mberExp = exp as MemberExpression;
211                     return mberExp;
212                 case "MethodBinaryExpression":
213                     var mbExp = exp as BinaryExpression;
214                     return getLeft ? mbExp.Left : mbExp.Right;
215                 case "UnaryExpression":
216                     var unaryExp = exp as UnaryExpression;
217                     return unaryExp;
218                 case "ConstantExpression":
219                     var cExp = exp as ConstantExpression;
220                     return cExp;
221                 case "InstanceMethodCallExpressionN":
222                     var imExp = exp as MethodCallExpression;
223                     return imExp;
224                 default:
225                     return null;
226             }
227         }
228         /// <summary>
229         /// 獲取變數名
230         /// </summary>
231         /// <param name="exp"></param>
232         /// <param name="isLeftChild"></param>
233         /// <returns></returns>
234         private string GetExpressionName(Expression exp)
235         {
236             var className = exp.GetType().Name;
237             switch (className)
238             {
239                 case "PropertyExpression":
240                 case "FieldExpression":
241                     var mberExp = exp as MemberExpression;
242                     return string.Format("{0}", mberExp.Member.Name);
243                 case "TypedParameterExpression":
244                     return _argName;
245                 default:
246                     return string.Empty;
247             }
248         }
249         /// <summary>
250         /// 獲取參數名
251         /// </summary>
252         /// <param name="exp"></param>
253         /// <param name="isLeftChild"></param>
254         /// <returns></returns>
255         private string GetParamName(Expression exp)
256         {
257             var className = exp.GetType().Name;
258             switch (className)
259             {
260                 case "PropertyExpression":
261                 case "FieldExpression":
262                     var mberExp = exp as MemberExpression;
263                     return string.Format("@{0}", mberExp.Member.Name);
264                 case "TypedParameterExpression":
265                     var texp = exp as ParameterExpression;
266                     return string.Format("@{0}", texp.Name);
267                 default:
268                     return string.Empty;
269             }
270         }
271         /// <summary>
272         /// 解析表信息
273         /// </summary>
274         /// <param name="exp"></param>
275         private void AnalysisTables(Expression exp)
276         {
277             var className = exp.GetType().Name;
278             switch (className)
279             {
280                 case "PropertyExpression":
281                 case "FieldExpression":
282                     var mberExp = exp as MemberExpression;
283                     if (!IsDefaultType(mberExp.Type))
284                     {
285                         if (!ResultData.TableList.ContainsKey(mberExp.Member.Name))
286                         {
287                             ResultData.TableList.Add(mberExp.Member.Name, new AnalysisTable()
288                             {
289                                 Name = mberExp.Type.Name,
290                                 TableType = mberExp.Type,
291                                 IsMainTable = false
292                             });
293                         }
294                     }
295                     AnalysisTables(mberExp.Expression);
296                     break;
297                 case "TypedParameterExpression":
298                     //命名參數表達式
299                     var texp = exp as ParameterExpression;
300                     if (!IsDefaultType(texp.Type))
301                     {
302                         if (!ResultData.TableList.ContainsKey(_argName))
303                         {
304                             ResultData.TableList.Add(_argName, new AnalysisTable()
305                             {
306                                 Name = texp.Type.Name,
307                                 TableType = texp.Type,
308                                 IsMainTable = true
309                             });
310                         }
311                     }
312                     break;
313                 default:
314                     break;
315             }
316         }
317         /// <summary>
318         /// 解析獲取表達式的值
319         /// </summary>
320         /// <param name="exp"></param>
321         /// <param name="leftChild"></param>
322         /// <returns></returns>
323         private object GetChildValue(Expression exp)
324         {
325             var className = exp.GetType().Name;
326             switch (className)
327             {
328                 case "BinaryExpression":
329                 case "LogicalBinaryExpression":
330                     var lExp = exp as BinaryExpression;
331                     var ret = GetChildValue(lExp.Left);
332                     if (IsNullDefaultType(ret))
333                     {
334                         ret = GetChildValue(lExp.Right);
335                     }
336                     return ret;
337                 case "MethodBinaryExpression":
338                     var mbExp = exp as BinaryExpression;
339                     var ret1 = GetChildValue(mbExp.Left);
340                     if (IsNullDefaultType(ret1))
341                     {
342                         ret1 = GetChildValue(mbExp.Right);
343                     }
344                     return ret1;
345 
346                 case "PropertyExpression":
347                 case "FieldExpression":
348                     var mberExp = exp as MemberExpression;
349                     return GetChildValue(mberExp.Expression);
350                 case "ConstantExpression":
351                     var cExp = exp as ConstantExpression;
352                     return cExp.Value;
353                 case "UnaryExpression":
354                     var unaryExp = exp as UnaryExpression;
355                     return GetChildValue(unaryExp.Operand);
356                 case "InstanceMethodCallExpressionN":
357                     var imExp = exp as MethodCallExpression;
358                     if (imExp.Arguments.Count > 0)
359                     {
360                         return GetChildValue(imExp.Arguments[0]);
361                     }
362                     return null;
363                 default:
364                     return null;
365             }
366 
367         }
368         /// <summary>
369         
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一:取字元串中第幾個字元 print "Hello"[0] 表示輸出字元串中第一個字元print "Hello"[-1] 表示輸出字元串中最後一個字元 二:字元串分割 print "Hello"[1:3] #第一個參數表示原來字元串中的下表#第二個闡述表示分割後剩下的字元串的第一個字元 在 原來字元 ...
  • 1.Tomcat記憶體溢出的原因 生產環境中Tomcat記憶體設置不好很容易出現記憶體溢出。造成記憶體溢出是不一樣的,當然處理方式也不一樣。 這裡根據平時遇到的情況和相關資料進行一個總結。常見的一般會有下麵三種情況: OutOfMemoryError: Java heap space OutOfMemory ...
  • This is a test 1 2 3 4 1 2 3 4 Code test ...
  • python多繼承,剛開始我是表示驚訝的,畢竟學的php,哪來的多繼承?頂多也就是利用介面模擬多繼承後者使用反射機制實現。那麼還是來看看python的強大吧 1 首先,Python的類繼承了多個類,那麼其尋找方法的方式有兩種,分別是:深度優先(經典類)和廣度優先(新式類) 2 共有與私有成員(很多的 ...
  • 本文翻譯自《effective modern C++》,由於水平有限,故無法保證翻譯完全正確,歡迎指出錯誤。謝謝! 如果你需要寫一個以名字作為參數,並記錄下當前日期和時間的函數,在函數中還要把名字添加到全局的數據結構中去的話。你可能會想出看起來像這樣的一個函數: std::multiset name ...
  • java的參數傳遞機制和C、C++其實很像,前兩天在改一個網站非同步介面的時候,掉入坑裡,之前是外包寫的代碼,springMVC里起了一個多線程,但是參數傳遞的時候傳的是一個model對象,所以所有線程都共用了這個對象,結果跑出來的result一塌糊塗。 下麵進入正題,先看一段demo代碼吧 java ...
  • 創建型模式抽象了實例化過程。它們幫助一個系統獨立於如何創建、組合和表示它的那些對象。 1.抽象工廠模式(ABSTRACT FACTORY) 意圖 提供一個創建一系列相關或相互依賴對象的介面,而不需指定他們具體的類。 ( 抽象工廠模式可以向客戶端(Client指代碼模式的使用者,後文類同)提供一個介面 ...
  • 翻譯前言:我在理解複雜事件處理(CEP)方面一直有這樣的困惑--為什麼這種計算模式是有效的,能夠分析得到有用的結果?為什麼它會快?我始終還沒有找到我期望的答案。不像map-reduce模型,google的論文非常清楚的描述了它的場景;或者disruptor框架,原作者清晰地解釋了它為什麼會快。在試圖... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...