新聞中心
這篇文章給大家介紹.NET如何深入解析LINQ框架,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
從事西云機(jī)房,服務(wù)器租用,云主機(jī),網(wǎng)絡(luò)空間,空間域名,CDN,網(wǎng)絡(luò)代維等服務(wù)。
一:LINQ執(zhí)行表達(dá)式
在研究LINQ的過程中,參考了很多技術(shù)文章還有技術(shù)書籍,毫無疑問的是Linq to Provider的調(diào)用入口都是將Lambda表達(dá)式解析成Expression
我們都是直接使用LINQ作為查詢接口,VS在最后編譯的時候負(fù)責(zé)對LINQ的語法進(jìn)行解析并且翻譯成對應(yīng)的擴(kuò)展方法調(diào)用。我們忽視一個重要的環(huán)節(jié),就是VS對LINQ進(jìn)行解析翻譯的時候是會執(zhí)行LINQ表達(dá)式的,這點(diǎn)非常重要。之前我一直以為VS只負(fù)責(zé)將LINQ的表達(dá)式翻譯成等價的擴(kuò)展方法調(diào)用,后來發(fā)現(xiàn)VS為了滿足我們在前期無法確定對象條件的情況下進(jìn)行Where字句的拼接,允許我們在編寫LINQ語句的時候帶有邏輯判斷表達(dá)式在里面,這個功能對我們進(jìn)行多條件組合查詢時相當(dāng)方便,不需要在進(jìn)行IF、ELSE的多個判斷,只需要順其自然的在LINQ中的第一個表達(dá)式中進(jìn)行判斷就行了。追求優(yōu)雅代碼的同志很不希望在一個既有LINQ查詢又帶有鏈?zhǔn)讲樵兊姆椒ㄖ杏脙煞N查詢方式,如果LINQ能滿足大部分的查詢功能那最完美;[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
為了說明LINQ在編譯時會被VS執(zhí)行,我們用LINQPad工具看一下便知;
LINQ查詢表達(dá)式:from truck in TB_CX_TRUCKs where 1==1 select truck
LINQ等價的鏈?zhǔn)椒椒ǎ?TB_CX_TRUCKs.Where (truck => True)
圖1:
如果沒有執(zhí)行按道理是直接解析成Lambda的格式(truck)=>1==1才對,然后讓LINQ to Provider提供程序負(fù)責(zé)處理才對,也許覺得沒有實(shí)質(zhì)的意思反正是恒等的表達(dá)式所以解析成這樣。我們在換一種寫法看看;[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
LINQ查詢表達(dá)式:from truck in TB_CX_TRUCKs where string.IsNullOrEmpty("1111") select truck
LINQ等價的鏈?zhǔn)椒椒ǎ篢B_CX_TRUCKs.Where (truck => String.IsNullOrEmpty ("1111"))
圖2:
由此可以得出一個結(jié)論,LINQ語句是會被執(zhí)行和解析的兩個動作,在還沒有進(jìn)入到提供程序時已經(jīng)可以看出LINQ是可以附帶一些執(zhí)行邏輯在里面的,而不是最終的SQL執(zhí)行邏輯。
表達(dá)式的處理可以分為常量表達(dá)式和動態(tài)變量表達(dá)式,常量表達(dá)式在VS編譯的時候就可以直接計算表達(dá)式是否是true、false。而動態(tài)變量表達(dá)式則需要在后期進(jìn)行表達(dá)式解析的時候計算的,換句話說Linq to Provider中的Provider提供程序是具有高智商的表達(dá)式執(zhí)行器,不僅僅是對表達(dá)式等價解析中間還夾雜著對表達(dá)式解析的自定義邏輯代碼。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
打個比方,我們都有過拼接查詢條件的經(jīng)歷,界面上有N個查詢條件字段,需要根據(jù)用戶是否填寫了哪個字段進(jìn)行動態(tài)的拼接進(jìn)LINQ語句中去。一般我們都會進(jìn)行if的判斷才行,因?yàn)槲覀兌加X得Where后面的條件表達(dá)式是直接被解析成對應(yīng)邏輯的SQL語句,所以只要拼接進(jìn)去的都是被解析成SQL的Where子句。由于LINQ是無法拆分開來進(jìn)行組裝的,必須一次寫完才能通過編譯。所以我們都在使用著查詢擴(kuò)展方法進(jìn)行數(shù)據(jù)查詢,這樣的困境使我們無法看到LINQ的優(yōu)雅,反而一直用不到。
通過觀察LINQPad工具解析的SQL語句,發(fā)現(xiàn)LINQ查詢表達(dá)式在提供程序內(nèi)部將被執(zhí)行、解析兩個過程,跟VS的過程是一樣的,能執(zhí)行先執(zhí)行,然后解析,解析是建立在前期執(zhí)行過后的基礎(chǔ)上的。我們還是來看一個比較簡單的LINQ解析后的SQL和鏈?zhǔn)椒椒?[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
LINQ查詢表達(dá)式:from truck in TB_CX_TRUCKs where 1==1 ||truck.LICENSE_NUMBER.Length<10 select truck
LINQ等價的鏈?zhǔn)椒椒ǎ篢B_CX_TRUCKs.Where (truck => (True || (truck.LICENSE_NUMBER.Length < 10)))
圖3:
對照鏈?zhǔn)椒椒?,很明顯VS先對1==1表達(dá)式進(jìn)行了執(zhí)行并返回true作為后面整個表達(dá)式的一部分拼接進(jìn)Where鏈?zhǔn)椒椒ǎ韵葓?zhí)行再解析兩個過程。然后我們對最后的SQL進(jìn)行分析,沒有看見任何Where語句,為什么呢?是因?yàn)樘峁┏绦蛟趦?nèi)部對表達(dá)式進(jìn)行了執(zhí)行并分析了我們想要的輸出結(jié)果,也不知道這樣的效果是不是為了滿足我們多條件拼接的問題。
由于Where方法里面的Lambda表達(dá)如果被執(zhí)行的話,那么將不會執(zhí)行(truck.LICENSE-NUMBER.Length<10),所以這點(diǎn)為我們的多條件拼接提供了接口。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
我們看一下多條件組合查詢示例:
將界面上的查詢實(shí)體傳入到數(shù)據(jù)訪問層之后:
public List
{
using (KJtest0817Entities DbContext = new KJtest0817Entities())
{
var resultList = from truck in DbContext.TB_CX_TRUCK
where string.IsNullOrEmpty(truckModel.ENGINE_NUMBER) || truck.ENGINE_NUMBER == truckModel.ENGINE_NUMBER
where string.IsNullOrEmpty(truckModel.LICENSE_NUMBER) || truck.ENGINE_NUMBER == truckModel.LICENSE_NUMBER
select new Truck()
{
BRAND = truck.BRAND
};
return resultList.ToList();
}
}
這樣的查詢LINQ確實(shí)很優(yōu)美,比起之前的IFELSE判斷也省事很多。
IQueryable
if (!string.IsNullOrEmpty(truckModel.LICENSE_NUMBER))
queryList = queryList.Where(truck => truck.LICENSE_NUMBER.Contains(truckModel.LICENSE_NUMBER));
if (!string.IsNullOrEmpty(truckModel.TRUCK_MODEL_CODE))
queryList = queryList.Where(truck => truck.TRUCK_MODEL_CODE.Contains(truckModel.TRUCK_MODEL_CODE));
如果有很多個查詢條件,那么我們將要寫很多這樣的判斷代碼,即不方便也不美觀。[王清培版權(quán)所有,轉(zhuǎn)載請給出署名]
多條件之間的OR查詢
盡管很多場合下我們都是使用Linq中的where關(guān)鍵字來拼接查詢條件,但是有一種需求Linq查詢確實(shí)滿足不了我們,那就是多條件之間是OR的關(guān)系。因?yàn)橹灰覀冇肔inq或者鏈?zhǔn)椒椒ǔ鰜淼膶懗鰜淼腟QL語句中的where條件后面將都是and關(guān)系,這個時候我們只能用鏈?zhǔn)椒椒▉磉M(jìn)行拆分才行。
public List
{
using (UserOrgDemo2Entities Context = new UserOrgDemo2Entities())
{
IQueryable
System.Linq.Expressions.Expression
if (!(dutyModel.RANK_NO == 0))
expressionDUTY.Or(duty => duty.RANK_NO == dutyModel.RANK_NO);
if (!string.IsNullOrEmpty(dutyModel.USER_PRIV))
expressionDUTY.Or(duty => duty.USER_PRIV == dutyModel.USER_PRIV);
return result.Where(expressionDUTY).Select(tb_duty=>new DutyModel(){ USER_PRIV=tb_duty.USER_PRIV}).ToList();
}
}
這里有個重點(diǎn)就是老外(估計是比較厲害的前輩,在此謝謝了!)寫的一個*.cs文件,里面是Expression
所有說如果多條件組合查詢之間是and關(guān)系可以直接使用Linq,如果是or或者是or與and一起,那么可以使用上面這種鏈?zhǔn)讲樵兎椒ā?/p>
其實(shí)說了那么多目的只有一個,LINQ的解析過程并非只有一個“提供程序翻譯成SQL”的過程,而是包括了兩個階段,四個過程的處理,LINQ的寫法很多種,原理應(yīng)該是差不多的,只要我們在寫LINQ的時候綜合考慮這幾個處理過程,應(yīng)該對我們應(yīng)對復(fù)雜的查詢很有幫助。
關(guān)于.NET如何深入解析LINQ框架就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
分享題目:.NET如何深入解析LINQ框架
標(biāo)題來源:http://www.dlmjj.cn/article/jepjos.html