日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
.NET如何深入解析LINQ框架

這篇文章給大家介紹.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表達(dá)式對象,跟Linq to Object不同,Linq to Object是將Lambda直接解析成泛型Func類型的委托,但是我們很多人包括我自己都忽視了一個很大的細(xì)節(jié),就是Provider在內(nèi)部將對Expression進(jìn)行執(zhí)行,并非我們所理解的那樣將表達(dá)式Expression對象完全解析成等價的SQL,也就是說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:

.NET如何深入解析LINQ框架

如果沒有執(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:

.NET如何深入解析LINQ框架

由此可以得出一個結(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:

.NET如何深入解析LINQ框架

對照鏈?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)載請給出署名]

我們看一下多條件組合查詢示例:

.NET如何深入解析LINQ框架

將界面上的查詢實(shí)體傳入到數(shù)據(jù)訪問層之后:

public List GetList(Truck truckModel)      
{      
    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 queryList = DbContext.TB_CX_TRUCK.AsQueryable();//初始化一個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)載請給出署名]

 .NET如何深入解析LINQ框架

多條件之間的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 GetList(DutyModel dutyModel)      
{      
    using (UserOrgDemo2Entities Context = new UserOrgDemo2Entities())      
    {      
        IQueryable result = Context.TB_DUTY.AsQueryable();      
        System.Linq.Expressions.Expression> expressionDUTY = DynamicLinqExpressions.True();

        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表達(dá)式文件的擴(kuò)展方法,主要就是用來進(jìn)行多條件Or、And之間組合查詢用的。

所有說如果多條件組合查詢之間是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