Linq To Sql是Microsoft開(kāi)發(fā)的針對(duì)解決data!=object問(wèn)題的新技術(shù)。在筆者的一系列的文章中,對(duì)它已經(jīng)做了大量的介紹?,F(xiàn)在,筆者將從經(jīng)驗(yàn)的角度,談?wù)勊膬?yōu)劣。
1、Linq To Sql的優(yōu)點(diǎn)
在Linq To Sql推出之前,我們只是把sql語(yǔ)句形成一個(gè)string,然后,通過(guò)ado.net傳給sql server,返回結(jié)果集.這里的缺陷就是,如果你sql語(yǔ)句寫(xiě)的有問(wèn)題,只有到運(yùn)行時(shí)才知道.而且并不所有的人都懂?dāng)?shù)據(jù)庫(kù)的。Linq To SQl 在一切圍繞數(shù)據(jù)的項(xiàng)目?jī)?nèi)都可以使用。特別是在項(xiàng)目中缺少sql server方面的專(zhuān)家時(shí),Linq To SQl的強(qiáng)大的功能可以幫我們快速的完成項(xiàng)目。Linq To SQl的推出,是讓大家從煩瑣的技術(shù)細(xì)節(jié)中解脫出來(lái),更加關(guān)注項(xiàng)目的邏輯。Linq To Sql的出現(xiàn),大大降低了數(shù)據(jù)庫(kù)應(yīng)用程序開(kāi)發(fā)的門(mén)楷,它實(shí)質(zhì)是事先為你構(gòu)架了數(shù)據(jù)訪問(wèn)層,勢(shì)必將加快數(shù)據(jù)庫(kù)應(yīng)用程序的開(kāi)發(fā)進(jìn)度。Linq To Sql解放了眾多程序員,讓他們的把更多的精力放到業(yè)務(wù)邏輯以及code上,而不是數(shù)據(jù)庫(kù)。對(duì)于初學(xué)者來(lái)講,Linq To Sql可以讓他們迅速進(jìn)入數(shù)據(jù)庫(kù)應(yīng)用程序開(kāi)發(fā)領(lǐng)域,節(jié)約了培訓(xùn)成本。
Linq To SQl 的實(shí)現(xiàn),是在ado.net和c#2.0的基礎(chǔ)上的。它通過(guò)自動(dòng)翻譯sql語(yǔ)句,并把結(jié)果集創(chuàng)建成對(duì)象并返回。這里我們可以看出,發(fā)送到Sql Server端的sql語(yǔ)句是Linq To Sql自動(dòng)生成的。這對(duì)不懂sql的人來(lái)說(shuō),無(wú)疑是個(gè)福音。第二,Linq To Sql語(yǔ)句是在編譯期間就做檢查的。而不是運(yùn)行時(shí)檢查。這樣,那里出了問(wèn)題,可以及時(shí)更改,而不是到了運(yùn)行時(shí)才發(fā)現(xiàn)問(wèn)題。第三,Linq To Sql是針對(duì)對(duì)象操作的,更符合今天的oo呼聲。
在Linq To SQl 之前,在java領(lǐng)域有Hibernate,在net領(lǐng)域有NHibernate技術(shù),來(lái)實(shí)現(xiàn)object/relational 持久和查詢服務(wù)。那和NHibernate比起來(lái),它又有那些優(yōu)勢(shì)呢.第一,影射代碼自動(dòng)生成。VS2008提供了SqlMetal和OR Designer兩個(gè)工具來(lái)完成此步驟。而在NHibernate中,你不得不自己手工寫(xiě)。第二,影射代碼有更多的選擇.NHibernate只能把數(shù)據(jù)庫(kù)的信息配置在一個(gè)xml中,而Linq To Sql有兩種方式,一個(gè)是放到xml中,我們稱(chēng)為Externl Mapping, 再一種就是以Attribute的形式,存在于各個(gè)property中。當(dāng)然,筆者本人并沒(méi)有使用過(guò)NHibernate,只是從資料上得到這些消息,所以無(wú)法給出更多的比較。
2、Linq To Sql的缺點(diǎn)
很久前,有個(gè)網(wǎng)友問(wèn)到這么一個(gè)問(wèn)題。他在界面上有個(gè)DataView,里面綁定了一些Column,然后他勾選那一列就按某列排序。其傳回的參數(shù)是列的名字。然后問(wèn)我該怎么用Dlinq 來(lái)實(shí)現(xiàn)。
在以前拼接Sql語(yǔ)句的年代,這個(gè)很簡(jiǎn)單,一個(gè)" order by " + string,想按什么排就按什么來(lái)排。而現(xiàn)在dlinq是用是一個(gè)對(duì)象的屬性,已經(jīng)不可能拼接了。我當(dāng)時(shí)給他的答案是這樣的。
以下是引用片段: private void Methods(string orderId) { var q = db.Customers.Select(c=>c); switch(orderId) { case "ID": q = q.OrderBy(c=>c.ID); break; case "Name": q = q.OrderBy(c=>c.Name); break; default: break; } var result = q.ToList(); } |
我那時(shí)也沒(méi)有想出一個(gè)更好的方案來(lái)。而后告訴他去查下Compiled Query,說(shuō)不定可以找到更方便的。后來(lái)我才在這個(gè)例子中,看到更方便的。
以下是引用片段: var query = db.Customers.Where("City == @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("New(CompanyName as Name, Phone)"); |
在這里OrderBy直接接收的就是列的名字。再仔細(xì)一看,好像Where里是Linq的語(yǔ)句哎,那OrderBy也該是linq語(yǔ)句。后來(lái),我把CompanyName換成小寫(xiě)的,一跑過(guò)了。莫非真的是列的名字?出個(gè)難題吧。找了一個(gè)列名,是帶空格的,重新來(lái)建這個(gè)工程.一跑,錯(cuò)了!把列名用中國(guó)擴(kuò)號(hào)擴(kuò)起來(lái)了,也是錯(cuò)了???,只是動(dòng)態(tài)構(gòu)造Expression Tree而已,永遠(yuǎn)都不能直接接收列的名字。這個(gè)例子看著是很簡(jiǎn)單,可不知道你有沒(méi)有注意到它有一個(gè)80多k的Dynamic.cs文件。更有意思的事情是,它的名稱(chēng)空間是System.Linq.Dynamic.看樣子,ms本來(lái)是打算把它加在.net3.5中嗎.不曉得為什么放到了例子中了。這個(gè)名稱(chēng)空間下,其主要內(nèi)容就是動(dòng)態(tài)構(gòu)造Expression Tree. 和Linq To Sql進(jìn)階系列(七)動(dòng)態(tài)查詢 一文中的方法類(lèi)似。只是,它還包含了解析字符串部分.
從上面那個(gè)例子中,可以看出,Linq To Sql在這種動(dòng)態(tài)構(gòu)造語(yǔ)句時(shí),比拼接sql麻煩很多。在Linq To Sql進(jìn)階系列(七)動(dòng)態(tài)查詢 一文中,筆者極力推薦使用object的查詢。這符合Linq To Sql的設(shè)計(jì)原則。因?yàn)?,它主要是為了解決data!=objects 的問(wèn)題而產(chǎn)生的.它所有的操作均針對(duì)object,那就讓我們使用object的查詢吧.
當(dāng)然,依然會(huì)有人習(xí)慣拼接字符串.我并不認(rèn)為這是個(gè)壞毛病。只是有點(diǎn)不符合oo思想而已。事實(shí)上,在Linq To Sql中,你依然可以使用拼接字符串的形式,而不使用它提供的Query Expression. 它提供了這么兩個(gè)接口,一個(gè)是,db.ExecuteQuery
看下面的例子:
以下是引用片段: var products = db.ExecuteQuery( "SELECT [Product List].ProductID, [Product List].ProductName " + "FROM Products AS [Product List] " + "WHERE [Product List].Discontinued = 0 " + "ORDER BY [Product List].ProductName;" ).ToList(); |
它返回的就是product的集合。而不是什么dataset和datatable之類(lèi)的。這里,你可以大膽的使用該函數(shù)繼續(xù)拼接你的sql吧,再看下面這個(gè):
以下是引用片段: db.ExecuteCommand("UPDATE Products SET UnitPrice = UnitPrice + 1.00"); |
它在做批處理的時(shí)候,你想不用它,都不行.當(dāng)然,你如果覺(jué)得性能不是問(wèn)題的話,那就用submitchange方法來(lái)做更新好了。簡(jiǎn)單明了的說(shuō),Linq To Sql在批處理更新的時(shí)候,SubmitChange只會(huì)一個(gè)個(gè)的更新。浪費(fèi)時(shí)間資源.而這個(gè)接口,恰好滿足了批處理更新或刪除的問(wèn)題。從這兩個(gè)例子,我們可以看出。沒(méi)有任何方案是萬(wàn)能的。各有各的優(yōu)點(diǎn)。
3、Linq To Sql的性能
Linq 的性能已經(jīng)被好多人提及.Linq To Object 的性能大家討論的比較多些.它確實(shí)比自己實(shí)現(xiàn)的查找要慢.但是當(dāng)數(shù)據(jù)量特別大時(shí),更多是時(shí)間是花在分配虛擬內(nèi)存上了,那么他們的差別就不是那么明顯了。Linq To Sql是又如何提升性能的?第一,采用延遲加載(deferred loading)技術(shù)。語(yǔ)句是聲明了,但是并不立即執(zhí)行,而是在真正需要的時(shí)候才執(zhí)行。第二,采用緩存技術(shù)。已經(jīng)取到內(nèi)存的數(shù)據(jù),再依次提取時(shí),會(huì)先從緩存中返回,而不是再次訪問(wèn)數(shù)據(jù)庫(kù)。當(dāng)然,筆者建議,不要對(duì)象的時(shí)候,沒(méi)有必要使用Linq To Sql.比如,只是填充DataView或DataGrid時(shí),返回dataset或datatable要比用Linq To Sql實(shí)現(xiàn)的快很多。
結(jié)論:各種技術(shù)都有其自身的優(yōu)點(diǎn)和缺點(diǎn)。使用什么樣的技術(shù),完全在于項(xiàng)目對(duì)性能和開(kāi)發(fā)進(jìn)度的要求,以及程序員自身的愛(ài)好有關(guān)。揚(yáng)長(zhǎng)避短,才是正道。