ASP.NET MVC & EF 構(gòu)建智能查詢(xún) 一、智能查詢(xún)的需求與設(shè)計(jì)
關(guān)于復(fù)用
在我們?nèi)粘5拈_(kāi)發(fā)過(guò)程中,代碼的復(fù)用其實(shí)是很重要的一部分,ASP.NET MVC框架本身為我們提供了很多很好的復(fù)用機(jī)制,讓我們能充分地利用它們來(lái)節(jié)省我們的Coding成本。
在簡(jiǎn)單的Coding中,我們可以通過(guò)構(gòu)造方法來(lái)實(shí)現(xiàn)代碼段的復(fù)用,在OOP編程中我們可以使用繼承多態(tài)來(lái)進(jìn)行類(lèi)的復(fù)用,我們也可以使用設(shè)計(jì)模式來(lái)做類(lèi)或?qū)ο箝g的代碼設(shè)計(jì)的復(fù)用,隨著程序的復(fù)雜我們就想構(gòu)造出更佳的復(fù)用方式,可以向更高層次上抽象。
應(yīng)用場(chǎng)景與目標(biāo)
在信息管理系統(tǒng)中我們會(huì)開(kāi)發(fā)大量的List頁(yè)面,它們功能上通常是非常相似的,一般是包含一個(gè)查詢(xún)條件組和一個(gè)列表。
例如下圖所示
那我的目標(biāo)呢,就是對(duì)這里面的查詢(xún)功能進(jìn)行封裝,以達(dá)到“只要更改頁(yè)面上的條件,就可以實(shí)現(xiàn)自動(dòng)的查詢(xún)邏輯”這樣的功能,即:如果我們要加一個(gè)查詢(xún)條件則不需要修改邏輯代碼只修改頁(yè)面即可。
其實(shí)對(duì)于一個(gè)有經(jīng)驗(yàn)的開(kāi)發(fā)人員呢,根據(jù)HTML頁(yè)面的查詢(xún)條件去自動(dòng)生成查詢(xún)結(jié)果并不是難事。最簡(jiǎn)單的是將查詢(xún)提交表單遍歷,然后連接成一個(gè)SQL進(jìn)行查詢(xún)。
但是使用SQL有很多問(wèn)題
- 注入問(wèn)題,因?yàn)椴恢李?lèi)型,所以很多地方都要拼寫(xiě)引號(hào)就算是使用Parameter,也無(wú)法處理類(lèi)型轉(zhuǎn)換的問(wèn)題
- 無(wú)法處理Or和And共存的問(wèn)題
- 無(wú)法處理其它查詢(xún)條件如大于小于Like
那我們想一下我們使用EF的話(huà)是如何正常去編寫(xiě)一個(gè)查詢(xún)的呢
我們通常是在邏輯中去拼SQL或是寫(xiě)如下的EF:
1: var query = db.User.AsQueryable();
2: if (string.IsNullOrEmpty(name))
3: query = query.Where(c => c.Name == name);
4: if (id.HasValue)
5: query = query.Where(c => c.Id == id);
6: if (string.IsNullOrEmpty(email))
7: query = query.Where(c => c.Email == email);
8: return query.ToList();
那我們的目標(biāo)其實(shí)就明確了,我們就是要讓代碼自動(dòng)去完成上述這一過(guò)程,并且可以支持
- 識(shí)別類(lèi)型(EF的話(huà)這個(gè)很重要)
- 僅查詢(xún)有效條件
- 處理可空類(lèi)型
- 處理類(lèi)型轉(zhuǎn)換(如DateTime與UnixTime的轉(zhuǎn)換)
- 一些代碼性邏輯(比如查詢(xún)某些日期的時(shí)候,其實(shí)我們要的結(jié)果并不是c=>c.Time==time而是c=>c.Time>time && c.Time<time.AddDays(1))
- 支持Or等 混合查詢(xún)
- 關(guān)于Like的相關(guān)處理
- 關(guān)于In操作的相關(guān)處理
- Join查詢(xún)的相關(guān)處理
理論流程
看一看我們要做的其實(shí)還挺多的,但是我已經(jīng)在心里搭出了一個(gè)這樣的流程,使用ASP.NET MVC及EF特性來(lái)完成這些功能
那其實(shí)呢首先的問(wèn)題就是我們從瀏覽器請(qǐng)求向服務(wù)器的時(shí)候,除了要查詢(xún)的字段,還應(yīng)該包含有 怎么查(就是操作符,比如= < > like in)、是否為Or、
而HTML中唯一可以直接傳到服務(wù)器的就是表單元素的name所以我們可以對(duì)name來(lái)做一些手腳讓它包含這些信息
比如[Equal]Id就表示讓Id這個(gè)屬性的值等于這個(gè)表單項(xiàng)的Value
[Equal]Id=
1
我們就利用這個(gè)postdata或QueryString去構(gòu)造出
c=>c.Id==1的Lambda表達(dá)式,并且支持多個(gè)條件
實(shí)際實(shí)現(xiàn)
而我是在Helper上加了一層擴(kuò)展來(lái)實(shí)現(xiàn)這樣的功能的,形如
1: <form action="" method="post">
2: 姓名:@Html.TextBox("Name").ForSearch(QueryMethod.Like)
3: Email:@Html.TextBox("Email").ForSearch(QueryMethod.Equal)<br />
4: Id: @Html.TextBox("Id").ForSearch(QueryMethod.Equal)
5: 生日: @Html.TextBox("Birthday").ForSearch(QueryMethod.Equal)<br />
6: <input type="submit" value="查詢(xún)" />
7: </form>
這里我們使用ForSearch這個(gè)擴(kuò)展為Html的name添加了前置的謂詞標(biāo)記[Equal]
我們?cè)诜?wù)器端只要統(tǒng)一處理
1: public ActionResult Index(QueryModel model)
2: {
3: using(var db=new DbEntities())
4: {
5: var list = db.Users.Where(model).ToList();
6: return View(list);
7: }
8:
9: }
我們是在這個(gè)Where的擴(kuò)展方法里重寫(xiě)了將QueryModel轉(zhuǎn)換成lambda表達(dá)式的工作,當(dāng)然在這之前我們還利用了自已實(shí)現(xiàn)的ModelBinder去將 postdata/querystring進(jìn)行了分析前初始化了QueryModel
在未來(lái)的幾篇中我們將會(huì)詳述這些過(guò)程的實(shí)現(xiàn)
ASP.NET MVC & EF 構(gòu)建智能查詢(xún) 二、模型的設(shè)計(jì)與ModelBinder


浙公網(wǎng)安備 33010602011771號(hào)