在很多時候,我們在資料庫裡面定義表欄位和實際在頁面中展示的內容,往往是不太匹配的,頁面數據可能是多個表數據的綜合體,因此除了我們在表設計的時候考慮周到外,還需要考慮數據展現的處理。如果是常規的處理,那麼需要對部分外鍵欄位進行特別的轉義處理,如果需要增加多一些欄位,那麼這種處理可能就相對比較麻煩一些。... ...
在很多時候,我們在資料庫裡面定義表欄位和實際在頁面中展示的內容,往往是不太匹配的,頁面數據可能是多個表數據的綜合體,因此除了我們在表設計的時候考慮周到外,還需要考慮數據展現的處理。如果是常規的處理,那麼需要對部分外鍵欄位進行特別的轉義處理,如果需要增加多一些欄位,那麼這種處理可能就相對比較麻煩一些。本文介紹如何在MVC控制器裡面使用dynamic和ExpandoObject,實現數據轉義後一體化的輸出,包括增加任意多的欄位信息。
1、數據信息的展示
一般情況下,我們在界面裡面展示的信息是相對比較豐富的,儘管我們設計數據表的時候,考慮的是如何精簡且避免重覆,但是在界面上展示的信息,往往是考慮如何讓用戶更加方便,因此可能儘可能的展示相關信息。
如對於這樣的場景,設備信息作為主要的基礎信息,其相關的業務包括設備檢查、設備維護、設備報修等信息,如下所示。
基於上面的數據設計,我們如果在展示設備檢查、設備維護、設備報修等信息的時候,那麼我們一般還需要展示部分的設備基礎信息,這樣我們更容易瞭解整個記錄數據,但是我們在數據設計的時候,是把它們分開的,因此需要在輸出到界面的時候,把它們綜合起來。
我以前在《基於MVC4+EasyUI的Web開發框架經驗總結(9)--在Datagrid裡面實現外鍵欄位的轉義操作》介紹過一些數據轉義的處理,不過那種方式並不是比較理想的方式。本篇介紹的使用dynamic和ExpandoObject才是我理想的處理模式。
我們來看看我最終通過這種方式實現的界面效果,之後我們再來一步步介紹如何實現這個操作過程的。
2、數據轉義的實現
在上面的界面效果裡面,我們是基於MVC實現後臺的處理,在界面上利用Bootstrap進行展示的(利用EaysUI組件也是類似的處理)。我們分為兩部分進行介紹實現的,一部分是採用MVC的輸出數據,一部分是界面的展示。
1)MVC的控制器數據處理
在MVC裡面,我們一般通過基類的FindWithPager進行數據的分頁處理,基於如何在MVC控制器裡面實現數據的分頁處理,大家感興趣可以參考《基於Metronic的Bootstrap開發框架經驗總結(2)--列表分頁處理和插件JSTree的使用》隨筆進行瞭解。
常規的做法,如果是主表信息,我們可以把它們簡單的輸出,如下所示。
public override ActionResult FindWithPager() { //檢查用戶是否有許可權,否則拋出MyDenyAccessException異常 base.CheckAuthorized(AuthorizeKey.ListKey); string where = GetPagerCondition(); PagerInfo pagerInfo = GetPagerInfo(); List<DeviceInfo> list = baseBLL.FindWithPager(where, pagerInfo); //Json格式的要求{total:22,rows:{}} //構造成Json的格式傳遞 var result = new { total = pagerInfo.RecordCount, rows = list }; return ToJsonContentDate(result); }
也就是不需要經過任何轉義就直接把查詢到的數據列表輸出給調用者,由界面進行數據的篩選處理。
如果對於上面提到的設備檢查、設備維修等和設備信息相關的,我們就需要利用dynamic和ExpandoObject,把設備信息整合一起提供給界面了,具體代碼如下所示。
我們首先對查詢的記錄進行遍歷,把每條記錄進行轉換,如下所示。
List<ExpandoObject> objList = new List<ExpandoObject>(); foreach (DeviceCheckInfo info in list) { dynamic obj = new ExpandoObject();
註意上面我們定義了List<ExpandoObject>的列表和dynamic obj的對象,這樣我們通過動態定義的對象,把我們需要的欄位屬性加到動態對象裡面,然後放到集合裡面即可。
完整的分頁控制器代碼如下所示。
public override ActionResult FindWithPager() { //檢查用戶是否有許可權,否則拋出MyDenyAccessException異常 base.CheckAuthorized(AuthorizeKey.ListKey); string where = GetPagerCondition(); PagerInfo pagerInfo = GetPagerInfo(); List<DeviceCheckInfo> list = baseBLL.FindWithPager(where, pagerInfo); //設備編碼 所屬科室 品牌 品類 型號 設備序列號 檢查時間 處理人 List<ExpandoObject> objList = new List<ExpandoObject>(); foreach (DeviceCheckInfo info in list) { dynamic obj = new ExpandoObject(); DeviceInfo deviceInfo = BLLFactory<Device>.Instance.FindByCode(info.DeviceCode); if (deviceInfo != null) { obj.Dept = deviceInfo.Dept; obj.Brand = deviceInfo.Brand; obj.Name = deviceInfo.Name; obj.Model = deviceInfo.Model; obj.SerialNo = deviceInfo.SerialNo; } obj.ID = info.ID; obj.DeviceCode = info.DeviceCode; obj.OperateTime = info.OperateTime; obj.Operator = info.Operator; objList.Add(obj); } //Json格式的要求{total:22,rows:{}} //構造成Json的格式傳遞 var result = new { total = pagerInfo.RecordCount, rows = objList }; return ToJsonContentDate(result); }
2)界面的數據展示
上面定義了數據的獲取方式,也就是我們需要任何數據都可以在MVC控制器裡面,通過動態屬性的方式添加到集合對象裡面,從而簡化了我們界面的處理,我們只需要把獲得的信息展示在界面上即可,非常簡便了。
界面視圖的HTML代碼如下所示
<table id="grid" class="table table-striped table-bordered table-hover" cellpadding="0" cellspacing="0" border="0" class="display" width="100%"> <thead id="grid_head"> <tr> <!--設備編碼 所屬科室 品牌 品類 型號 設備序列號 檢查時間 處理人 --> <th class="table-checkbox" style="width:40px"><input class="group-checkable" type="checkbox" onclick="selectAll(this)"></th> <th>設備編碼</th> <th>所屬科室</th> <th>品牌</th> <th>品類</th> <th>型號</th> <th>設備序列號</th> <th>檢查時間</th> <th>處理人</th> <th style="width:90px">操作</th> </tr> </thead> <tbody id="grid_body"></tbody> </table>
我們綁定到界面上,是通過Ajax的方式獲取數據,然後綁定顯示的,JS代碼如下所示。
function SearchCondition(page, condition) { //獲取Json對象集合,並生成數據顯示內容 url = "/DeviceCheck/FindWithPager?page=" + page + "&rows=" + rows; $.getJSON(url + "&" + condition, function (data) { $("#totalCount").text(data.total); $("#totalPageCount").text(Math.ceil(data.total / rows)); $("#grid_body").html(""); //<!--設備編碼 所屬科室 品牌 品類 型號 設備序列號 檢查時間 處理人 --> $.each(data.rows, function (i, item) { var tr = "<tr>"; tr += "<td><input class='checkboxes' type=\"checkbox\" name=\"checkbox\" value=" + item.ID + "></td>"; tr += "<td>" + item.DeviceCode + "</td>"; tr += "<td>" + item.Dept + "</td>"; tr += "<td>" + item.Brand + "</td>"; tr += "<td>" + item.Name + "</td>"; tr += "<td>" + item.Model + "</td>"; tr += "<td>" + item.SerialNo + "</td>"; tr += "<td>" + item.OperateTime + "</td>"; tr += "<td>" + item.Operator + "</td>"; tr += getActionHtml(item.ID); //獲取查看、編輯、刪除操作代碼 tr += "</tr>"; $("#grid_body").append(tr); }); //設置分頁屬性及處理 var element = $('#grid_paging'); if(data.total > 0) { var options = { bootstrapMajorVersion: 3, currentPage: page, numberOfPages: rows, totalPages: Math.ceil(data.total / rows), onPageChanged: function (event, oldPage, newPage) { SearchCondition(newPage, condition); //頁面變化時觸發內容更新 } } element.bootstrapPaginator(options); } else { element.html(""); } }); }
這樣就最終優雅的實現了我們前面介紹的界面效果了。