LinqToDB 源碼分析——設計原理
我們知道實現了IQueryable<T>接口和IQueryProvider接口就可以使用Linq To SQL的功能。關于如何去實現的話,上一章也為我們引導了一個方向。LinqToDB框架也是順著這個方向進行的。然而筆者對LinqToDB框架的作者真的很無語。如果有打開過LinqToDB框架源碼的朋友,可能會發現很多代碼都沒有文字說明。這無疑給那些想要深入了解框架的人加大了前進力度。本來筆者以為只是沒有相關代碼說明不用怕。只要找到對應的文檔應該沒有什么大問題。于是筆者也跟很多人一樣子——去作者的github上找。結果只有教大家如何使用。卻對框架沒有進行任何說明。筆者又想也許作者比較懶吧。可能只有在他的博客上才有相關的文檔吧。結果筆者很失望——沒有找到任何有幫助的東西。唉!為了能獲得更多的資料筆者還購買了V*N。所以想要了解LinqToDB框架只有一個方式——硬著頭皮啃代碼。顯然這種做法就是從代碼中尋找作者的思路和理念。同時不可否認存在猜測上的錯誤。必竟作者的隨意一段代碼就有可能導至理解上的誤導。希望讀者們能夠理解。
LinqToDB框架的原理
正如上面所講的,LinqToDB框架也是按上一章中講到的三個大至步驟進行的。所以我們的目標也變得很明確——了解LinqToDB框架是如何實現這三大步驟的。
1.實現Linq提供的IQueryable<T>接口和IQueryProvider接口。生成相關的表達式樹。 2.把對應的表達式樹轉化生成對應數據庫的SQL語句。并執行。 3.根據映射的信息,生成對應的集合類。
從上一章的例子中我們可以看到LinqToDB框架以DataContext類作為入口類。這一點顯然跟Entity Framework一樣子。都是以某個類做為上下文引動整個框架。如果你們看過github上的例子的話,就會發現筆者用的入口類跟作者不太一樣子。作者用的是DataConnection類。事實上不管是DataConnection類還是DataContext類他們都繼承了IDataContext接口。所以在使用上來講,不會差太多。只是在筆者看來他們之間的職責卻存在很大的差別。不過筆者還是不太明白作者這樣子設計的目的。DataConnection類能做DataContext類的大部分事情,卻又擁有自己獨有的職責——負責存取當前數據庫的信息。讓筆者感覺DataConnection類在職責上有一點重復了。這也是為什么筆者認為DataContext類才是LinqToDB框架入口類。至少讓筆者覺得DataContext類比較明確。
上面這張圖片是描述了LinqToDB框架在查詢時候的一個原理圖。是筆者根據代碼的運行路線整理出來的。主要的目地就是為了方便導引大家深入,少走一點彎路。我們知道要實現Linq查詢很簡單,就是上面的三個步驟。可是要實現這三個步驟的事情卻很多。圖片上只是顯示主要核心類切口。可以說這三個步驟就是靠圖片上的類進行工作的。
加載數據數庫信息
LinqToDB框架并沒有直接就將實現IQueryable<T>和IQueryProvider的類交出來。而是以上下文的思維方式間接性的引導出來。這也是合理的設計。必竟在生成表達式樹和SQL語句之前,我們有必要知道數據庫的相關信息。比如當前數據庫是用什么——Sql Server還是MySql。而這個工作任務交給圖中的DataConnection。這味意著LinqToDB框架在進入上面所講的第一步的時候,就已經知道數據庫的信息了。但是作者并沒有直接性的設置數據庫的信息。而是通過IDataProvider接口實例來提供。這樣子更加區別出DataContext類只是用于引導的職責。如果你們使用過增刪改的話,你們可能會覺得不對。他不是可以會增刪改嗎?事實上如果你們用心點的話,就會現他們都是靜態擴展方法。
生成表達式樹
通過DataContext類我們就可以拿到我們的集合表(這里的集合表是指實現ITable接口的實例)。ITable接口作用跟Entity Framework的IDbSet接口很相近。從代碼中我們可能看到他來自于IExpressionQuery接口。相信大家看到名字就明白IExpressionQuery接口的實現類就是圖片中的ExpressionQuery類。這個時候上面說的第一步工作開始進行了。ExpressionQuery類就是對應的實現IQueryable<T>接口和IQueryProvider接口的類。當然,LinqToDB框架用的是IQueryable<T>接口的子接口——IOrderedQueryable<T>。生成表達式樹的工作也在這里進展開始了。
執行數據庫
要實現Linq查詢的功能主要難點在如何去處理表達式樹,在通過表達式樹生成對應的T-SQL。LinqToDB框架通過一個核心類Query來作中間過度。筆者喜歡把他叫中間者。作者在設計用到Query類時候,并不是把他直接實例出來。而是通過ExpressionBuilder類進行進一步的加工,把相關的信息分配來Query類實例,在返回Query類實例。那么對于ExpressionBuilder類的職責筆者用一倆句話是很難說清楚。這里只能大概講他是用于處理表達式樹的。其中不得不用到一個叫SelectQuery類的。這個類很重要。他會參與最后生成T-SQL工作里面去。筆者想說通過ExpressionBuilder類加工之后,對應的是查詢還是增刪改都會記錄在SelectQuery類實例里面。就相當于生成T-SQL的信息都存放在SelectQuery類實例里面。
Query類的工作職責比較復雜。當經歷過處理表達式樹的過程之后,Query類就具備生成T-SQL的能力了。為什么這樣子講呢?這個時候Query類擁有生成T-SQL的SelectQuery類實例和結果集的映射信息MapInfo類實例。所以生成T-SQL也只是一個時間問題。在生成T-SQL的這個過程看起來簡單,事實上卻有很多細節要處理。作者讓LinqToDB框架通過DataConnection類去調用BasicSqlBuilder類的子類來處理生成T-SQL。當然這一個過程里面離不開SelectQuery類。只是作者并不是直接提交T-SQL,而是生成一個叫PreparedQuery類實例。PreparedQuery類用于存放執行數據庫的信息。這也是最后一步了。通過PreparedQuery類實例生成XxxCommand類執行數據庫。在通過MapInfo類實例轉化為對應的集合數據。
結束語
好了。對于LinqToDB框架的原理筆者就介紹在這里。本系列的后面章節也是依據本章的思路進行的。看看作者是什么樣子設計LinqToDB框架的。又有什么值得我們去學習的。
來自:http://www.cnblogs.com/hayasi/p/6055528.html