天天看點

Linq将何去何從

微軟的EntityFramework随着.net Framework 3.5sp1一起釋出了,這個Entity Framework 雖然與linq to sql同為orm架構,但絕非linq to sql的更新。

EntityFramework的風格更像ado.net的标準寫法,查詢語句并非linq風格,而是普通的字元串。這好像與 Hibernate的HQL又走到了一起。

在我看來,EntityFramework 的推出基本上就意味着linq to sql退出曆史舞台。而Linq 就如高樓還未建成,就缺了最主要的那根頂梁柱,難有完工那一天了。

Linq是.net Framework 3.5力推的程式設計特性,号稱将改變程式員的程式設計習慣的東西,在之前推出的一系列如擴充方法,var類型,都是為linq打基礎。但是現在不得不說,Linq還沒來得及風光,好日子恐怕就要過去了。

Entity Framework為何不再linq to sql基礎上發展,而采用ado.net的傳統風格?我想主要還是Linq自身的一些缺陷。

首先linq的風格雖然華麗,但是寫法和其他代碼格格不入,影響整體布局。

其次linq的寫法不能支援動态附加的查詢條件(要加條件隻能直接使用Where()這樣的擴充方法)。linq的查詢語句,翻譯成擴充方法,就是方法鍊的風格,而你無法在不使方法鍊中斷的情況下,動态的指定到底執行鍊中的哪些方法。而如果采用字元串作為查詢語句,那麼就靈活多了——你可以随意的拼湊字元串,直至最終得到你所需的。

最後一個問題,也是linq最大的硬傷:linq查詢語句本身就是程式執行的一部分。就因為這,使得在程式運作時還沒來得及對整條語句進行分析,就已經不得不開始執行一些子句了。select子句必須寫在最後就是這個問題的最直接證明。當然這個問題的影響遠遠不止select子句的位置那麼簡單。因為運作時無法對linq語句有個整體的分析,是以這個工作不得不被放到了編譯期,但是編譯期所能獲得的資訊與運作時不可同日而語,光是最重要的一點:實際資料庫的情況,在編譯時,編譯器對它就一無所知。

就因為這個原因,很多複雜的查詢功能,linq不是實作不了,就是實作起來很複雜,并且大部分情況都得在linq語句的這裡那裡嵌滿擴充方法,反而不優雅。又比如更新,就會先查詢再更新;删除會一條條删除,不會直接批量删除。

再拿最簡單的外連接配接抓取(orm架構并不常需要顯式作連接配接查詢,但由于lazy-loading産生的n+1問題,外連接配接抓取是一種提高性能的方案)來說,在linq中就必須用 join ...into形式的句式将結果選入一個臨時變量,然後再另開一個from子句将臨時變量中結果選出,如

var res  =  from p  in  ctx.Products

                       join c  in  ctx.Categories

                       on p.CategoryID equals c.CategoryID

                       into pro

                       from x  in  pro.DefaultIfEmpty()

                       select p.ProductName;

複雜程度甚至還遠遠超過sql的外連接配接查詢。

而如果采用字元串作為查詢語句,那麼在運作時對查詢語句進行解析就變得輕而易舉,查詢語句能力理論上也就可以和sql做得一樣強大。

是以我認為,最後所提的這個問題就是導緻Entity Framework舍棄linq風格,回歸字元串的主要原因。

從概念上講,Entity Framework雖然後于linq to sql出來,但是linq to sql更有未來感,很前衛很激進。但微軟走這條路顯然不順利,無論前面為它做了多少準備,多少鋪墊,到最後發現還是走不下去。而Entity Framework則是一種理性的回歸,更務實更保守,它的這條路,Hibernate早在幾年前已經走通了,是以技術上不會有任何問題。