日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

QueryBuilder : 打造优雅的Linq To SQL动态查询

發(fā)布時(shí)間:2024/4/11 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QueryBuilder : 打造优雅的Linq To SQL动态查询 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先我們來(lái)看看日常比較典型的一種查詢(xún)Form

這個(gè)場(chǎng)景很簡(jiǎn)單:就是根據(jù)客戶(hù)名、訂單日期、負(fù)責(zé)人來(lái)作篩選條件,然后找出符合要求的訂單。

在那遙遠(yuǎn)的時(shí)代,可能避免不了要寫(xiě)這樣的簡(jiǎn)單接口:

public interface IOrderService {IList<Order> Search(string customer, DateTime dateFrom, DateTime dateTo, int employeeID); }

具體愛(ài)怎么實(shí)現(xiàn)就怎么實(shí)現(xiàn)啦,存儲(chǔ)過(guò)程,ORM框架。這里假定是用了孩童時(shí)代就開(kāi)始有的存儲(chǔ)過(guò)程吧:

Create Procedure usp_SearchOrder @Customer nVarchar(20), @DateFrom DateTime, @DateTo DateTime, @EmployeeID Int AS /*... 以下省去幾百行SQL語(yǔ)句*/

接著寫(xiě)一個(gè)類(lèi)OrderService實(shí)現(xiàn)IOrderService, 調(diào)用以上存儲(chǔ)過(guò)程,洋洋灑灑的寫(xiě)上幾句代碼就可以“安枕睡覺(jué)”了。但是,噩夢(mèng)就從此開(kāi)始了。

客戶(hù)的需求是不斷變化的。過(guò)了一段時(shí)間,設(shè)計(jì)這個(gè)接口的工程師就先被夸贊一番,然后說(shuō)客戶(hù)提出需要加多“一個(gè)”篩選條件。工程師可能也想過(guò)這一點(diǎn),加一個(gè)篩選條件“不外乎“給接口加個(gè)參數(shù),存儲(chǔ)過(guò)程加個(gè)參數(shù),where那里加個(gè)條件,……苦力活一堆。

客戶(hù)的篩選條件是這樣:既然訂單里有“國(guó)家”字段,就想根據(jù)國(guó)家來(lái)篩選條件,并且國(guó)家可多選,如下圖:

工程師看到圖可能就倒下了……

以上可以當(dāng)作笑話(huà)看看,不過(guò)話(huà)說(shuō)回來(lái),沒(méi)有一個(gè)通用的查詢(xún)框架,單靠這樣的接口

public interface IOrderService {IList<Order> Search(string customer, DateTime dateFrom, DateTime dateTo, int employeeID); }

是根本不能適應(yīng)需求變化。

在沒(méi)有Linq 的時(shí)代, SQL“ 強(qiáng)人”就試圖通過(guò)拼接字符串的方法來(lái)結(jié)束存儲(chǔ)過(guò)程帶來(lái)的痛苦,

IList<Order> Search(string sqlQurey);

結(jié)果進(jìn)入另一個(gè)被“SQL注入”的時(shí)代(注:我大學(xué)時(shí)也有一段時(shí)間玩過(guò)“SQL注入”,不亦樂(lè)乎,現(xiàn)在基本上很少找到能夠簡(jiǎn)單注入的網(wǎng)站了,有磨難就有前進(jìn)的動(dòng)力嘛)。

來(lái)到Linq To SQL 的時(shí)代 (不得不贊嘆Linq把查詢(xún)發(fā)揮到淋漓盡致), 某些朋友就能輕易地?fù)]灑Linq表達(dá)式來(lái)解決查詢(xún)問(wèn)題:

IList<Order> Search(Expression<Func<Order, bool>> expression);

查詢(xún)語(yǔ)句:

Expression<Func<Order, bool>> expression = c =>c.Customer.ContactName.Contains(txtCustomer.Text) &&c.OrderDate >= DateTime.Parse(txtDateFrom.Text) && c.OrderDate <= DateTime.Parse(txtDateTo.Text) &&c.EmployeeID == int.Parse(ddlEmployee.SelectedValue);

然后再一次 “安枕睡覺(jué)”。一覺(jué)醒來(lái)還是不行。

客戶(hù)又來(lái)新需求:負(fù)責(zé)人的下拉框加個(gè)“ALL”的選項(xiàng),如果選了“ALL”就搜索所有的負(fù)責(zé)人相關(guān)的Order。

工程師刷刷幾下,又加if else,又加 and 來(lái)拼裝expression;接著又來(lái)新需求,…… 最后expression臃腫無(wú)比 (當(dāng)然這個(gè)故事是有點(diǎn)夸張)。

為什么用上“先進(jìn)”的工具還是會(huì)倒在慘不忍睹的代碼海洋里呢?因?yàn)镸icrosoft提供給我們的只是“魚(yú)竿”。這種魚(yú)竿不管在小河還是大海都能釣到東西,而且不管你釣的是鯊魚(yú)還是鯨魚(yú),也保證魚(yú)竿不會(huì)斷。但是有些人能釣到大魚(yú),有些則釣到一雙拖鞋。因?yàn)殛P(guān)鍵的魚(yú)餌沒(méi)用上。也就是說(shuō),Microsoft給了我們強(qiáng)大的Linq 表達(dá)式,可不是叫我們隨便到表現(xiàn)層一放就了事,封裝才是硬道理。

于是,千呼萬(wàn)喚始出來(lái),猶抱 QueryBuilder 半遮臉:

var queryBuilder = QueryBuilder.Create<Order>().Like(c => c.Customer.ContactName, txtCustomer.Text).Between(c => c.OrderDate, DateTime.Parse(txtDateFrom.Text), DateTime.Parse(txtDateTo.Text)).Equals(c => c.EmployeeID, int.Parse(ddlEmployee.SelectedValue)).In(c => c.ShipCountry, selectedCountries );

這樣代碼就清爽很多了,邏輯也特別清晰,即使不懂Linq 表達(dá)式的人也能明白這些語(yǔ)句是干什么的,因?yàn)樗恼Z(yǔ)義基本上跟SQL一樣:

WHERE ([t1].[ContactName] LIKE '%A%') AND ? (([t0].[OrderDate]) >= '1/1/1990 12:00:00 AM') AND (([t0].[OrderDate]) <= '9/25/2009 11:59:59 PM') AND ? (([t0].[EmployeeID]) = 1) AND ? ([t0].[ShipCountry] IN ('Finland', 'USA', 'UK'))

?

對(duì)于使用這個(gè)QueryBuilder的人來(lái)說(shuō),他覺(jué)得很爽,因?yàn)樗靼揍炇裁呆~(yú)用什么魚(yú)餌了,模糊查詢(xún)用Like,范圍用Between,……

對(duì)于編寫(xiě)這個(gè)QueryBuilder的人來(lái)說(shuō),也覺(jué)得很爽,因?yàn)樗旧頍釔?ài)寫(xiě)通用型的代碼,就像博客園的老趙那樣。

?

看到使用方式,聰明人自然就已經(jīng)想到大概的實(shí)現(xiàn)方式。就像廚師吃過(guò)別人煮的菜,自然心中也略知是怎么煮的。

實(shí)現(xiàn)方式并不難,這里簡(jiǎn)單說(shuō)明一下:

QueryBuilder.Create<Order>() 返回的是IQueryBuilder<T> 接口,而IQueryBuilder<T> 接口只有一個(gè) Expression 屬性:

/// <summary> /// 動(dòng)態(tài)查詢(xún)條件創(chuàng)建者 /// </summary> /// <typeparam name="T"></typeparam> public interface IQueryBuilder<T> {Expression<Func<T, bool>> Expression { get; set; } }

于是 Like, Between, Equals, In就可以根據(jù)這個(gè)Expression 來(lái)無(wú)限擴(kuò)展了。

以下是實(shí)現(xiàn)Like的擴(kuò)展方法:

/// <summary> /// 建立 Like ( 模糊 ) 查詢(xún)條件 /// </summary> /// <typeparam name="T">實(shí)體</typeparam> /// <param name="q">動(dòng)態(tài)查詢(xún)條件創(chuàng)建者</param> /// <param name="property">屬性</param> /// <param name="value">查詢(xún)值</param> /// <returns></returns> public static IQueryBuilder<T> Like<T>(this IQueryBuilder<T> q, Expression<Func<T, string>> property, string value) {value = value.Trim();if (!string.IsNullOrEmpty(value)){var parameter = property.GetParameters();var constant = Expression.Constant("%" + value + "%");MethodCallExpression methodExp = Expression.Call(null, typeof(SqlMethods).GetMethod("Like",new Type[] { typeof(string), typeof(string) }), property.Body, constant);Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);q.Expression = q.Expression.And(lambda);}return q; }

每個(gè)方法都是對(duì)Expression進(jìn)行修改,然后返回修改后的Expression,以此實(shí)現(xiàn)鏈?zhǔn)骄幊獭?/p>

稍微有點(diǎn)意思的就是 In的擴(kuò)展方法(這個(gè)害我費(fèi)了不少時(shí)間,前前后后可能4個(gè)小時(shí)):

/// <summary> /// 建立 In 查詢(xún)條件 /// </summary> /// <typeparam name="T">實(shí)體</typeparam> /// <param name="q">動(dòng)態(tài)查詢(xún)條件創(chuàng)建者</param> /// <param name="property">屬性</param> /// <param name="valuse">查詢(xún)值</param> /// <returns></returns> public static IQueryBuilder<T> In<T,P>(this IQueryBuilder<T> q, Expression<Func<T, P>> property, params P[] values) {if (values != null && values.Length > 0){var parameter = property.GetParameters();var constant = Expression.Constant(values);Type type = typeof(P);Expression nonNullProperty = property.Body;//如果是Nullable<X>類(lèi)型,則轉(zhuǎn)化成X類(lèi)型if (IsNullableType(type)){type = GetNonNullableType(type);nonNullProperty = Expression.Convert(property.Body, type);}Expression<Func<P[], P, bool>> InExpression = (list, el) => list.Contains(el);var methodExp = InExpression;var invoke = Expression.Invoke(methodExp, constant, property.Body);Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(invoke, parameter);q.Expression = q.Expression.And(lambda);}return q; }

?

如果有興趣的朋友可以在文章末下載源代碼,看看其他兩個(gè)擴(kuò)展方法。

嗯,似乎又是時(shí)候退場(chǎng)了。什么?你說(shuō)只有Like, Between, Equals, In不夠用?哦,可以自己擴(kuò)展IQueryBuilder,自己動(dòng)手豐衣足食嘛。

我后來(lái)又為另外一個(gè)Project做了一個(gè)“奇怪”的擴(kuò)展:

譬如,我們知道打印設(shè)置里可以直接寫(xiě)頁(yè)數(shù)號(hào)碼來(lái)篩選要打印哪幾頁(yè)——1,4,9 或者 1-8 這樣的方式。

于是引發(fā)這樣的需求:

左圖查詢(xún)Bruce和Jeffz的訂單;右圖查詢(xún)B直到Z的客戶(hù)訂單。

還美其名曰:Fuzzy ,意即:模糊不清的 (點(diǎn)這里看 Fuzzy詳細(xì)意思)

總結(jié):

其實(shí)這篇文章已經(jīng)醞釀好久了,近期工作收獲很多編程技巧。一個(gè)Project下來(lái)了,又是時(shí)候總結(jié)一下,希望有空能夠繼續(xù)與大家分享。

源代碼下載:CoolCode.Linq.rar

建議參考新一篇《QueryBuilder : 打造優(yōu)雅的Linq To SQL動(dòng)態(tài)查詢(xún)(支持EF、.Net4)

參考:

http://www.cnblogs.com/neuhawk/archive/2007/07/07/809585.html

http://www.cnblogs.com/billgan/archive/2009/01/08/1371809.html

http://www.cnblogs.com/lyj/archive/2008/03/25/1122157.html

http://www.cnblogs.com/126/archive/2007/09/09/887723.html

超強(qiáng)干貨來(lái)襲 云風(fēng)專(zhuān)訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

總結(jié)

以上是生活随笔為你收集整理的QueryBuilder : 打造优雅的Linq To SQL动态查询的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日本高清有码视频 | 蜜桃做爰免费网站 | 国产av一区不卡 | 成人快色| 日本精品一区二区三区视频 | 午夜久久久久久久久久 | 青青草原在线免费观看视频 | 一区二区三区www | 欧美精品久久久久久久久 | 日日干干 | 免费视频中文字幕 | 久久亚洲高清 | 国产群p视频 | 精国产人伦一区二区三区 | 91精品国自产在线 | 麻豆人妻少妇精品无码专区 | 日本色站 | 国产精品高潮呻吟视频 | 婷婷九月综合 | jlzzjlzz欧美大全 | 中文字幕第6页 | 少妇高潮大叫好爽喷水 | 欧美日韩国产成人精品 | 丁香啪啪综合成人亚洲 | 在线观看中文字幕2021 | 国产成人亚洲精品无码h在线 | 爽妇网国产精品 | 四虎国产在线 | 久久男女 | sese久久| 欧美成人吸奶水做爰 | 国产激情久久久久 | 国产欧美日韩激情 | 在线免费看av| 丰满熟女人妻一区二区三 | 日韩伦乱| 亚洲成人激情小说 | 区一区二区三 | 日本福利在线 | 神马久久午夜 | www.欧美色| 午夜少妇 | 天天干天天操天天爽 | 成人黄色小说视频 | 亚洲国产福利视频 | 亚洲福利在线视频 | 色吧在线视频 | 超碰黄色| 精品中文字幕av | 法国极品成人h版 | 亚洲性视频 | 午夜精品久久久久久久久久久久久 | 精品国产乱码久久久久久蜜柚 | 国产精品久久久久久久久免费 | 波多野结衣视频免费 | 久久一区二区三区四区五区 | 亚洲精品中文字幕在线 | 女仆裸体打屁屁羞羞免费 | 久久综合88| 免费观看一区二区 | 九九99精品视频 | 免费看av毛片 | a√天堂在线| 看成人片| 日本成人精品在线 | 阿v免费视频 | 国产精品丝袜黑色高跟 | 99久久精品国产亚洲 | 亚洲a∨无码无在线观看 | 国产一区二区三区在线视频观看 | 一区二区三区影院 | 久久久久久久久久久久久av | 中文字幕乱码中文字幕 | 午夜黄色在线 | 欧美日韩一区二区三区 | 国产小视频你懂的 | 黄色二级毛片 | 99精品视频在线播放免费 | 美女黄色在线观看 | 天堂av观看 | 国产三级国产精品国产国在线观看 | 国产精品二区一区二区aⅴ污介绍 | 九九热视频在线播放 | 91丨九色丨蝌蚪丨对白 | 日日夜夜精品免费视频 | 牛牛精品一区二区 | 97在线视频人妻无码 | 黄色综合网站 | 综合天天色 | 大陆极品少妇内射aaaaa | 天天看毛片 | 午夜成人免费视频 | 性午夜| 成人午夜福利一区二区 | 97在线免费视频 | 狼人精品一区二区三区在线 | 熟女少妇在线视频播放 | 日韩中文字幕综合 | 欧美视频一区在线 |