Linq查詢的原理


我們在學習Linq的時候會見到一些很常見的關鍵詞語。比如Linq To SQL、Linq To Objects、Linq To XML等。事實這些一般都是根據(jù)不同的數(shù)據(jù)源來進行命名的。 說實話筆者當初學習的時候,看到這些命名險些以為只有這幾種。事實不是這樣子的。Linq有倆個核心類——Enumerable類和Queryable類。這倆個類可以說貫穿整個Linq知識體系。如果有心的朋友可以點開對應的dll包就是發(fā)現(xiàn)他們都在System.Linq命名空間下。同時他們都是用于擴展相應的靜態(tài)方法。而且方法名大至相同。然后他們卻在本質上有著細微的差別。Enumerable類是對IEnumerable<T>接口進行擴展并且傳入了Func類型的參數(shù)。數(shù)據(jù)源是來自于內存中的。而Queryable類是對IQueryable<T>接口進行擴展,傳入?yún)?shù)是表達式(Expression類型)。數(shù)據(jù)源是來自于第三方。比如SQL Server、MySql等。

Linq的思想就是提供一個統(tǒng)一模型操作來處理數(shù)據(jù)。所以本質來講對數(shù)據(jù)源不是很講究。比如數(shù)據(jù)源是文件,或則說數(shù)據(jù)源是Excel之類的。相信可能有人已經看到過Linq To Excel呢?主要辛苦還是這些開發(fā)底層的人。對于使用者來講沒有什么多大的差別。Linq現(xiàn)在面對數(shù)據(jù)源而擴展功能有很多。其中專對數(shù)據(jù)庫來講,最流行還是有Linq To SQL。而且擴展數(shù)據(jù)庫的Linq功能大多數(shù)都用IQueryable<T>接口。當然,這不是說用IEnumerable<T>接口就不行了。只是這倆種接口在實現(xiàn)上有著很大的差別。IEnumerable<T>接口我們都知道他一般是專對于內存的。這意味著我們必須把相應的數(shù)據(jù)全部加載到內存中才可以進行查詢。這樣子的操作太傷性能了。而IQueryable<T>接口我們可以巧妙的用上表達式樹(Expression Tree)進行轉化生成對應的數(shù)據(jù)庫SQL語句,然后在執(zhí)行數(shù)據(jù)庫。這才是顯得合理。

ORM思想能流行大體上可以說是因為他的思想更加貼切于人類的思維方式。在筆者看來如果把Linq技術說成也是ORM思想的產物之一,這樣子的說法也不為過。這也是筆者喜歡Linq的地方。LinqToDB框架只所以都能支持Linq。不可否認也是依據(jù)這一種上面所講的原理來實現(xiàn)的。大體的想法如下。

  1. 實現(xiàn)Linq提供的IQueryable<T>接口和IQueryProvider接口。生成相關的表達式樹。
  2. 把對應的表達式樹轉化生成對應數(shù)據(jù)庫的SQL語句。并執(zhí)行。
  3. 根據(jù)映射的信息,生成對應的集合類。(這里的集合類是指SQL語句執(zhí)行結果轉成類放入的集合)

實現(xiàn)自定義的Linq查詢一定離不開倆類——IQueryable<T>接口和IQueryProvider接口。上面的工作可以說都在這倆類上面。IQueryable<T>接口一般用于生成對應的表達式樹。而IQueryProvider接口用于執(zhí)行表達式樹,轉化成對應的SQL語句,執(zhí)行數(shù)據(jù)庫并生成映射的模型對象。

注意:IQueryable<T>接口是什么樣子生成相關的表達式樹呢?讓筆者來講的話,筆者覺得有一點浪費時間。但是不要當心博客園里面有一位大神寫的博文一定能滿足你——王清培的《.NET深入解析LINQ框架》

實現(xiàn)Linq查詢


支持Linq查詢本意上就是實現(xiàn)上面所講的倆個接口。當你實現(xiàn)IQueryable<T>接口的時候,VS提示你實現(xiàn)三個屬性。如果你F12進去查看他有些什么內容的話,你會發(fā)現(xiàn)什么也沒有。為了方便筆者還是把他貼出來了。

IQueryable<T>接口:

網友評論