ASP.NET MVC & EF 構建智能查詢 二、模型的設計與ModelBinder

作者: 重典  來源: 博客園  發布時間: 2010-12-29 16:39  閱讀: 7172 次  推薦: 7   原文鏈接   [收藏]  

  在第一篇中,我講解了我們要做智能查詢的原因,以及基本的解決方案設計。從這篇開始我們開始講解它的實現過程。

  其實在寫這一系列文章之初,我其實是想由底至上去講解,但是我又整理了一遍代碼才發現,其實如果不了解最表面的東西,也是不太好深入的。

  所以我們的第二篇文章就來講一下我們這個智能查詢框架中最淺,但也是使用最頻繁的部分,也就是Model。

  首先我們的Entity  或者說數據庫的結構如下:

image  另外如下面代碼,我們有一個用于傳遞name=value對,及查詢謂詞的model:

 
public ActionResult Index(QueryModel model)
{

using(var db=new DbEntities())
{
var list
= db.Users.Where(model).ToList();
return View(list);
}
}

  我命名之為QueryModel。它由Action的參數傳入,再傳入EF的Where擴展方法,它是構建Lambda表達式的原型,上面是我們的一個通用的查詢Action的代碼。

  而QueryModel的代碼為:

image  QueryModel的唯一一個屬性Items,是一個ConditionItem的集合,它里面存著所有的查詢條件。而ConditionItem里面的屬性:

  1. Field表示要查詢的目標屬性的名稱,我們的設定它是支持子屬性查詢的,例如 “Profile.MyUser.Id”。
  2. Method則是當前使用的謂詞,它是QueryMethod的一個枚舉值。
  3. OrGroup是一個字符串,是一個OrGroup的多個表達式將會以Or操作符進行關聯,然后再And。
  4. Prefix是一個分類的前綴,我們假定一個Action可能處理多個查詢條件組的時候為了分開這些查詢條件而加的屬性。
  5. Value則是這個表達試的值。

  而我們在頁面上類似:

 
<form action="" method="post">
姓名:<input id="Name" name="[Like]Name" type="text" value="" />
Email:<input id="Email" name="[Equal]Email" type="text" value="" /><br />
Id: <input id="Id" name="[Equal]Id" type="text" value="" />
生日: <input id="Birthday" name="[Equal]Birthday" type="text" value="" /><br />
<input type="submit" value="查詢" />
</form>

  這樣的表單,我們提交到服務器端,我們要進行ASP.NET MVC 中IModelBinder的轉換,要將querystring 或 postdata中的KeyValuePair轉換為我們的ConditionItem。

  當然,我們除了謂詞Method之外,還有Prefix以及OrGroup要從客戶端提交過來所以我們就要制定一個規則,我們約定:

  1. 中括號[]中的為查詢謂詞
  2. 小括號()中的為前綴Prefix
  3. 大括號{}中的為OrGroup

  我們可以通過以下IModelBinder的實現將Request.QueryString或Request.Form中的值轉換到QueryModel中:

 
public class SearchModelBinder : IModelBinder
{

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model
= (QueryModel)(bindingContext.Model ?? new QueryModel());
var dict
= controllerContext.HttpContext.Request.Params;
var keys
= dict.AllKeys.Where(c => c.StartsWith("["));//我們認為只有[開頭的為需要處理的
if (keys.Count() != 0)
{

foreach (var key in keys)
{

if (!key.StartsWith("[")) continue;
var val
= dict[key];
//處理無值的情況
if (string.IsNullOrEmpty(val)) continue;
AddSearchItem(model, key, val);
}
}

return model;
}


/// <summary>
/// 將一組key=value添加入QueryModel.Items
/// </summary>
/// <param name="model">QueryModel</param>
/// <param name="key">當前項的HtmlName</param>
/// <param name="val">當前項的值</param>
public static void AddSearchItem(QueryModel model, string key, string val)
{

string field = "", prefix = "", orGroup = "", method = "";
var keywords
= key.Split(']', ')', '}');
//將Html中的name分割為我們想要的幾個部分
foreach (var keyword in keywords)
{

if (Char.IsLetterOrDigit(keyword[0])) field = keyword;
var last
= keyword.Substring(1);
if (keyword[0] == '(') prefix = last;
if (keyword[0] == '[') method = last;
if (keyword[0] == '{') orGroup = last;
}

if (string.IsNullOrEmpty(method)) return;
if (!string.IsNullOrEmpty(field))
{
var item
= new ConditionItem
{
Field
= field,
Value
= val.Trim(),
Prefix
= prefix,
OrGroup
= orGroup,
Method
= (QueryMethod) Enum.Parse(typeof (QueryMethod), method)
};
model.Items.Add(item);
}
}
}

  當然我們還要在Global.asax中添加:

 
ModelBinders.Binders.Add(typeof (QueryModel), new SearchModelBinder());

  這樣我們就可以在Action中獲取到相應的查詢條件了:

image  我們可以看到,從表單提交過來的數據我們已經正確地存放在QueryModel中了。

7
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()