ASP.NET MVC & EF 構建智能查詢 二、模型的設計與ModelBinder
在第一篇中,我講解了我們要做智能查詢的原因,以及基本的解決方案設計。從這篇開始我們開始講解它的實現過程。
其實在寫這一系列文章之初,我其實是想由底至上去講解,但是我又整理了一遍代碼才發現,其實如果不了解最表面的東西,也是不太好深入的。
所以我們的第二篇文章就來講一下我們這個智能查詢框架中最淺,但也是使用最頻繁的部分,也就是Model。
首先我們的Entity 或者說數據庫的結構如下
另外如下面代碼,我們有一個用于傳遞name=value對,及查詢謂詞的model
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: }
我命名之為QueryModel。它由Action的參數傳入,再傳入EF的Where擴展方法,它是構建Lambda表達式的原型,上面是我們的一個通用的查詢Action的代碼。
而QueryModel的代碼為
QueryModel的唯一一個屬性Items,是一個ConditionItem的集合,它里面存著所有的查詢條件。
而ConditionItem里面的屬性
- Field表示要查詢的目標屬性的名稱,我們的設定它是支持子屬性查詢的,例如 “Profile.MyUser.Id”
- Method則是當前使用的謂詞,它是QueryMethod的一個枚舉值
- OrGroup是一個字符串,是一個OrGroup的多個表達式將會以Or操作符進行關聯,然后再And
- Prefix是一個分類的前綴,我們假定一個Action可能處理多個查詢條件組的時候為了分開這些查詢條件而加的屬性
- Value則是這個表達試的值
而我們在頁面上類似
1: <form action="" method="post">
2: 姓名:<input id="Name" name="[Like]Name" type="text" value="" />
3: Email:<input id="Email" name="[Equal]Email" type="text" value="" /><br />
4: Id: <input id="Id" name="[Equal]Id" type="text" value="" />
5: 生日: <input id="Birthday" name="[Equal]Birthday" type="text" value="" /><br />
6: <input type="submit" value="查詢" />
7: </form>
這樣的表單,我們提交到服務器端,我們要進行ASP.NET MVC 中IModelBinder的轉換,要將querystring 或 postdata中的KeyValuePair轉換為我們的ConditionItem。
當然,我們除了謂詞Method之外,還有Prefix以及OrGroup要從客戶端提交過來所以我們就要制定一個規則
我們約定
- 中括號[]中的為查詢謂詞
- 小括號()中的為前綴Prefix
- 大括號{}中的為OrGroup
我們可以通過以下IModelBinder的實現將Request.QueryString或Request.Form中的值轉換到QueryModel中:
1: public class SearchModelBinder : IModelBinder
2: {
3: public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
4: {
5: var model = (QueryModel)(bindingContext.Model ?? new QueryModel());
6: var dict = controllerContext.HttpContext.Request.Params;
7: var keys = dict.AllKeys.Where(c => c.StartsWith("["));//我們認為只有[開頭的為需要處理的
8: if (keys.Count() != 0)
9: {
10: foreach (var key in keys)
11: {
12: if (!key.StartsWith("[")) continue;
13: var val = dict[key];
14: //處理無值的情況
15: if (string.IsNullOrEmpty(val)) continue;
16: AddSearchItem(model, key, val);
17: }
18: }
19: return model;
20: }
21:
22: /// <summary>
23: /// 將一組key=value添加入QueryModel.Items
24: /// </summary>
25: /// <param name="model">QueryModel</param>
26: /// <param name="key">當前項的HtmlName</param>
27: /// <param name="val">當前項的值</param>
28: public static void AddSearchItem(QueryModel model, string key, string val)
29: {
30: string field = "", prefix = "", orGroup = "", method = "";
31: var keywords = key.Split(']', ')', '}');
32: //將Html中的name分割為我們想要的幾個部分
33: foreach (var keyword in keywords)
34: {
35: if (Char.IsLetterOrDigit(keyword[0])) field = keyword;
36: var last = keyword.Substring(1);
37: if (keyword[0] == '(') prefix = last;
38: if (keyword[0] == '[') method = last;
39: if (keyword[0] == '{') orGroup = last;
40: }
41: if (string.IsNullOrEmpty(method)) return;
42: if (!string.IsNullOrEmpty(field))
43: {
44: var item = new ConditionItem
45: {
46: Field = field,
47: Value = val.Trim(),
48: Prefix = prefix,
49: OrGroup = orGroup,
50: Method = (QueryMethod) Enum.Parse(typeof (QueryMethod), method)
51: };
52: model.Items.Add(item);
53: }
54: }
55: }
當然我們還要在Global.asax中添加
1: ModelBinders.Binders.Add(typeof (QueryModel), new SearchModelBinder());
這樣我們就可以在Action中獲取到相應的查詢條件了
我們可以看到,從表單提交過來的數據我們已經正確地存放在QueryModel中了。



浙公網安備 33010602011771號