DDD領域驅動設計初探(7):Web層的搭建
來自: http://blog.jobbole.com/99390/
前言:好久沒更新博客了,每天被該死的業務纏身,今天正好一個模塊完成了,繼續來完善我們的代碼。之前的六篇完成了領域層、應用層、以及基礎結構層的部分代碼,這篇打算搭建下UI層的代碼。
一、UI層介紹
在DDD里面,UI層的設計也分為BS和CS,本篇還是以Web為例來說明。我們的Web采用的是MVC+bootstrap的架構。Table組件使用的是bootstrap table,之所以用它是因為它的API比較全,并且博主覺得它的風格適用于各種類型的設備,無論是PC端還是手機端都都能很好的兼容各種瀏覽器。
這里還是貼出bootstrap API的相關地址。
Bootstrap中文網: http://www.bootcss.com/
Bootstrap Table Demo: http://issues.wenzhixin.net.cn/bootstrap-table/index.html
Bootstrap Table API: http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/
Bootstrap Table源碼: https://github.com/wenzhixin/bootstrap-table
Bootstrap DataPicker: http://www.bootcss.com/p/bootstrap-datetimepicker/
二、代碼示例
上篇完成了WCF的設計代碼,但是具體的業務邏輯的代碼還沒有,我們先來實現具體業務的CURD代碼。
1、WCF代碼
1.1 WCF服務業務接口代碼
///
/// 權限管理模塊接口契約
///
[ServiceContract]
[ServiceInterface]
public interface IPowerManageWCFService
{
#region 用戶管理
[OperationContract]
List GetUsers(ExpressionNode expressionNode);
[OperationContract]
DTO_TB_USERS AddUser(DTO_TB_USERS oUser);
[OperationContract]
bool DeleteUser(DTO_TB_USERS oUser);
[OperationContract]
bool DeleteUserByLamada(ExpressionNode expressionNode);
[OperationContract]
bool UpdateUser(DTO_TB_USERS oUser);
#endregion
#region 部門管理
[OperationContract]
List GetDepartments(ExpressionNode expressionNode);
[OperationContract]
DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept);
[OperationContract]
bool DeleteDepartment(DTO_TB_DEPARTMENT oDept);
[OperationContract]
bool DeleteDeptByLamada(ExpressionNode expressionNode);
[OperationContract]
bool UpdateDepartment(DTO_TB_DEPARTMENT oDept);
#endregion
#region 角色管理
[OperationContract]
List GetRoles(ExpressionNode expressionNode);
[OperationContract]
DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole);
#endregion
#region 菜單管理
[OperationContract]
List GetMenus(ExpressionNode expressionNode);
[OperationContract]
DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu);
#endregion
}
1.2 WCF接口實現代碼:
[ServiceClass]
public class PowerManageWCFService :BaseService, IPowerManageWCFService
{
#region Fields
[Import]
private IUserRepository userRepository { get; set; }
[Import]
private IDepartmentRepository departmentRepository { get; set; }
[Import]
private IRoleRepository roleRepository { get; set; }
[Import]
private IMenuRepository menuRepository { get; set; }
#endregion
#region Constust
public PowerManageWCFService()
{
}
#endregion
#region WCF服務接口實現
#region 用戶管理
//這里參數為什么不直接用Expression>這種類型,是因為Expression不支持序列化,無法用于WCF數據的傳遞
public List GetUsers(ExpressionNode expressionNode)
{
Expressionbool>> selector = null;
if (expressionNode != null)
{
selector = expressionNode.ToExpressionbool>>();
}
var lstRes = base.GetDtoByLamada(userRepository, selector);
return lstRes;
}
public DTO_TB_USERS AddUser(DTO_TB_USERS oUser)
{
return base.AddDto(userRepository, oUser);
}
public bool DeleteUser(DTO_TB_USERS oUser)
{
var bRes = false;
try
{
base.DeleteDto(userRepository, oUser);
bRes = true;
}
catch
{
}
return bRes;
}
public bool DeleteUserByLamada(ExpressionNode expressionNode)
{
Expressionbool>> selector = null;
if (expressionNode != null)
{
selector = expressionNode.ToExpressionbool>>();
}
var bRes = false;
try
{
base.DeleteDto(userRepository, selector);
bRes = true;
}
catch
{
}
return bRes;
}
public bool UpdateUser(DTO_TB_USERS oUser)
{
var bRes = false;
try
{
base.UpdateDto(userRepository, oUser);
bRes = true;
}
catch
{
}
return bRes;
}
#endregion
#region 部門管理
public List GetDepartments(ExpressionNode expressionNode)
{
Expressionbool>> selector = null;
if (expressionNode != null)
{
selector = expressionNode.ToExpressionbool>>();
}
return base.GetDtoByLamada(departmentRepository, selector);
}
public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept)
{
return base.AddDto(departmentRepository, oDept);
}
public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept)
{
var bRes = false;
try
{
base.DeleteDto(departmentRepository, oDept);
bRes = true;
}
catch
{
}
return bRes;
}
public bool DeleteDeptByLamada(ExpressionNode expressionNode)
{
Expressionbool>> selector = null;
if (expressionNode != null)
{
selector = expressionNode.ToExpressionbool>>();
}
var bRes = false;
try
{
base.DeleteDto(departmentRepository, selector);
bRes = true;
}
catch
{
}
return bRes;
}
public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept)
{
var bRes = false;
try
{
base.UpdateDto(departmentRepository, oDept);
bRes = true;
}
catch
{
}
return bRes;
}
#endregion
#region 角色管理
public List GetRoles(ExpressionNode expressionNode)
{
Expressionbool>> selector = null;
if (expressionNode != null)
{
selector = expressionNode.ToExpressionbool>>();
}
return base.GetDtoByLamada(roleRepository, selector);
}
public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole)
{
return base.AddDto(roleRepository, oRole);
}
#endregion
#region 菜單管理
public List GetMenus(ExpressionNode expressionNode)
{
Expressionbool>> selector = null;
if (expressionNode != null)
{
selector = expressionNode.ToExpressionbool>>();
}
return base.GetDtoByLamada(menuRepository, selector);
}
public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu)
{
return base.AddDto(menuRepository, oMenu);
}
#endregion
#endregion
}
這里要說明一點,在通過lamada表達式查詢的方法里面為什么不直接用Expression>這種類型,而要使用ExpressionNode這種類型的變量呢?
這是因為Expression不支持序列化,無法用于WCF數據的傳遞。ExpressionNode這個對象的使用需要添加Serialize.Linq這個dll的引用,還好有我們神奇的NuGet,讓我們再也不用去網上找一大堆的dll了。

我們公用的增刪改查封裝到了BaseService這個父類里面。
1.3 BaseService代碼
public class BaseService
{
#region Fields
private bool bInitAutoMapper = false;
#endregion
#region Construct
public BaseService()
{
//注冊MEF
Regisgter.regisgter().ComposeParts(this);
}
#endregion
#region 查詢
///
/// 通用單表查詢方法
///
/// DTOmodel
/// 領域模型
/// 需要傳過來的倉儲接口對象
/// 前端傳過來的lamada表達式
///
public List GetDtoByLamada(IRepository oRepository, Expressionbool>> selector = null)
where DomainModel : AggregateRoot
where DtoModel : Dto_BaseModel
{
InitAutoMapper();
if (selector == null)
{
var lstDomainModel = oRepository.Entities.ToList();
return Mapper.Map, List>(lstDomainModel);
}
//得到從Web傳過來和DTOModel相關的lamaba表達式的委托
Funcbool> match = selector.Compile();
//創建映射Expression的委托
Func mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(Mapper.Engine).Compile();
//得到領域Model相關的lamada
Expressionbool>> lamada = ef_t => match(mapper(ef_t));
List list = oRepository.Find(lamada).ToList();
return Mapper.Map, List>(list);
}
#endregion
#region 新增
public DtoModel AddDto(IRepository oRepository, DtoModel oDtoModel)
where DomainModel : AggregateRoot
where DtoModel : Dto_BaseModel
{
InitAutoMapper();
var oDomain = Mapper.Map(oDtoModel);
oRepository.Insert(oDomain);
return Mapper.Map(oDomain);
}
#endregion
#region 刪除
public int DeleteDto(IRepository oRepository, DtoModel oDtoModel)
where DomainModel : AggregateRoot
where DtoModel : Dto_BaseModel
{
InitAutoMapper();
var oDomain = Mapper.Map(oDtoModel);
return oRepository.Delete(oDomain);
}
public int DeleteDto(IRepository oRepository, Expressionbool>> selector = null)
where DomainModel : AggregateRoot
where DtoModel : Dto_BaseModel
{
InitAutoMapper();
if (selector == null)
{
return 0;
}
//得到從Web傳過來和DTOModel相關的lamaba表達式的委托
Funcbool> match = selector.Compile();
//創建映射Expression的委托
Func mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(Mapper.Engine).Compile();
//得到領域Model相關的lamada
Expressionbool>> lamada = ef_t => match(mapper(ef_t));
return oRepository.Delete(lamada);
}
#endregion
#region 更新
public void UpdateDto(IRepository oRepository, DtoModel oDtoModel)
where DomainModel : AggregateRoot
where DtoModel : Dto_BaseModel
{
InitAutoMapper();
var oDomain = Mapper.Map(oDtoModel);
oRepository.Update(oDomain);
}
#endregion
#region Private
private void InitAutoMapper()
{
var oType = Mapper.FindTypeMapFor();
if (oType==null)
{
Mapper.CreateMap();
Mapper.CreateMap();
}
}
#endregion
}
這個父類主要做了兩件事:一是MEF的初始化;二是通用增刪改查的實現。所有dto對象和領域model的映射都在這里統一管理。
2、UI層代碼
UI層里面,為了更好分離代碼,我們引入了接口編程的機制,引入了ESTM.Web.IBLL和ESTM.Web.BLL兩個項目,如圖:

為什么要有這么一個接口層?之前 MEF實現設計上的“松耦合”(終結篇:面向接口編程) 這篇已經做過介紹,對面向接口編程不了解的朋友可以看看。
2.1 ESTM.Web.IBLL代碼
這個dll主要定義接口規則。
public interface IPowerManager
{
List GetUsers(Expressionbool>> selector = null);
DTO_TB_USERS AddUser(DTO_TB_USERS oUser);
bool DeleteUser(DTO_TB_USERS oUser);
bool UpdateUser(DTO_TB_USERS oUser);
bool DeleteUser(Expressionbool>> selector = null);
List GetDepartments(Expressionbool>> selector = null);
DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept);
bool DeleteDepartment(DTO_TB_DEPARTMENT oDept);
bool DeleteDepartment(Expressionbool>> selector = null);
bool UpdateDepartment(DTO_TB_DEPARTMENT oDept);
List GetRoles(Expressionbool>> selector = null);
List GetMenus(Expressionbool>> selector = null);
}
2.2 ESTM.Web.BLL代碼
這個dll用于實現ESTM.Web.IBLL里面的接口方法
[Export(typeof(IPowerManager))]
public class PowerManager : IPowerManager
{
#region Fields
//創建WCF服務連接對象
private ServiceReference_PowerManager.PowerManageWCFServiceClient oService = CreatePowerManagerService.GetInstance();
#endregion
#region 接口實現
public List GetUsers(Expressionbool>> selector = null)
{
return oService.GetUsers(GetExpressionNode(selector));
}
public List GetDepartments(Expressionbool>> selector = null)
{
return oService.GetDepartments(GetExpressionNode(selector));
}
public List GetRoles(Expressionbool>> selector = null)
{
return oService.GetRoles(GetExpressionNode(selector));
}
public List GetMenus(Expressionbool>> selector = null)
{
return oService.GetMenus(GetExpressionNode(selector));
}
#endregion
#region Privates
//將lamada表達式轉換為可用于WCF傳遞的ExpressionNode類型
private ExpressionNode GetExpressionNode(Expressionbool>> selector)
{
if (selector == null)
{
return null;
}
ExpressionConverter expressionConverter = new ExpressionConverter();
ExpressionNode expressionNode = expressionConverter.Convert(selector);
return expressionNode;
}
#endregion
public DTO_TB_USERS AddUser(DTO_TB_USERS oUser)
{
return oService.AddUser(oUser);
}
public bool DeleteUser(DTO_TB_USERS oUser)
{
return oService.DeleteUser(oUser);
}
public bool DeleteUser(Expressionbool>> selector = null)
{
if (selector == null)
{
return false;
}
ExpressionConverter expressionConverter = new ExpressionConverter();
ExpressionNode expressionNode = expressionConverter.Convert(selector);
return oService.DeleteUserByLamada(expressionNode);
}
public bool UpdateUser(DTO_TB_USERS oUser)
{
return oService.UpdateUser(oUser);
}
public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept)
{
return oService.AddDepartment(oDept);
}
public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept)
{
return oService.DeleteDepartment(oDept);
}
public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept)
{
return oService.UpdateDepartment(oDept);
}
public bool DeleteDepartment(Expressionbool>> selector = null)
{
if (selector == null)
{
return false;
}
ExpressionConverter expressionConverter = new ExpressionConverter();
ExpressionNode expressionNode = expressionConverter.Convert(selector);
return oService.DeleteDeptByLamada(expressionNode);
}
}
public class CreatePowerManagerService
{
private static ServiceReference_PowerManager.PowerManageWCFServiceClient oPowerManagerClient = null;
private static object obj = new object();
public static ServiceReference_PowerManager.PowerManageWCFServiceClient GetInstance()
{
lock (obj)
{
if (oPowerManagerClient == null)
{
oPowerManagerClient = new ServiceReference_PowerManager.PowerManageWCFServiceClient();
}
}
return oPowerManagerClient;
}
}
由于是采用的添加服務引用的方式引用的WCF服務,所以在這一層需要添加WCF服務的引用。在實現這部分代碼的時候博主遇到過一個問題,在此和朋友們分享一下。由于在WCF服務的設計里面用到了DTO對象,而在ESTM.Web.BLL這個項目里面也要用到DTO,但是添加WCF服務引用的時候默認的是WCF服務里面的DTO,而不是ESTM.Common.DtoModel這個項目的DTO對象,這樣就有問題了,每次如果我們需要改動下dto的內容,那么我們就需要更新下服務引用。還好,微軟給我們選擇的機制,我們來看圖


這樣就能解決上面的問題了。
2.3 ESTM.Web代碼
按照面向接口的機制,ESTM.Web項目是不需要添加ESTM.Web.BLL這個實現層項目引用的,通過MEF動態導入ESTM.Web.BLL里面的對象。我們來看代碼:
public class PowerManagerController : BaseController
{
[Import]
private IPowerManager PowerManager { set; get; }
#region Views
// GET: PowerManager
public ActionResult User()
{
return View();
}
public ActionResult Role()
{
return View();
}
public ActionResult Menu()
{
return View();
}
public ActionResult Department()
{
return View();
}
#endregion
#region 部門管理
public JsonResult GetDepartments(int limit, int offset, string departmentname, string statu)
{
//得到lamada表達式
var oLamadaExtention = new LamadaExtention();
if (!string.IsNullOrEmpty(departmentname))
{
oLamadaExtention.GetExpression("DEPARTMENT_NAME", departmentname, ExpressionType.Contains);
}
if (!string.IsNullOrEmpty(statu))
{
oLamadaExtention.GetExpression("STATUS", statu, ExpressionType.Contains);
}
var lamada = oLamadaExtention.GetLambda();
var lstRes = PowerManager.GetDepartments(lamada);
return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
}
public object GetDepartmentEdit(string strPostData)
{
var oDepartment = Newtonsoft.Json.JsonConvert.DeserializeObject(strPostData);
if (string.IsNullOrEmpty(oDepartment.DEPARTMENT_ID))
{
oDepartment.DEPARTMENT_ID = Guid.NewGuid().ToString();
oDepartment = PowerManager.AddDepartment(oDepartment);
}
else
{
PowerManager.UpdateDepartment(oDepartment);
}
return oDepartment;
}
public object DeleteDept(string strID)
{
PowerManager.DeleteDepartment(x=>x.DEPARTMENT_ID == strID);
return new object();
}
#endregion
#region 菜單管理
public JsonResult GetMenus(int limit, int offset, string menuname, string menuurl)
{
var oLamadaExtention = new LamadaExtention();
if (!string.IsNullOrEmpty(menuname))
{
oLamadaExtention.GetExpression("MENU_NAME", menuname, ExpressionType.Contains);
}
if (!string.IsNullOrEmpty(menuurl))
{
oLamadaExtention.GetExpression("MENU_URL", menuurl, ExpressionType.Contains);
}
var lamada = oLamadaExtention.GetLambda();
var lstRes = PowerManager.GetMenus(lamada).ToList();
return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
}
public object GetMenuEdit(string strPostData)
{
var oMenu = Newtonsoft.Json.JsonConvert.DeserializeObject(strPostData);
if (string.IsNullOrEmpty(oMenu.MENU_ID))
{
//oMenu = MenuManager.Add(oMenu);
}
else
{
//MenuManager.Update(oMenu);
}
return oMenu;
}
public object DeleteMenu(string strID)
{
//MenuManager.Delete(strID);
return new object();
}
public object GetParentMenu()
{
var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "1");
//var lstRes = RoleManager.Find().ToList();
//var oRes = new PageRowData();
//oRes.rows = lstRes.Skip(offset).Take(limit).ToList();
//oRes.total = lstRes.Count;
return lstMenu; ;
}
public object GetChildrenMenu(string strParentID)
{
var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "2" & x.PARENT_ID == strParentID).ToList();
//var lstRes = RoleManager.Find().ToList();
//var oRes = new PageRowData();
//oRes.rows = lstRes.Skip(offset).Take(limit).ToList();
//oRes.total = lstRes.Count;
return lstMenu; ;
}
#endregion
#region 權限管理
public JsonResult GetRole(int limit, int offset, string rolename, string desc)
{
var oLamadaExtention = new LamadaExtention();
if (!string.IsNullOrEmpty(rolename))
{
oLamadaExtention.GetExpression("ROLE_NAME", rolename, ExpressionType.Contains);
}
if (!string.IsNullOrEmpty(desc))
{
oLamadaExtention.GetExpression("DESCRIPTION", desc, ExpressionType.Contains);
}
var lamada = oLamadaExtention.GetLambda();
var lstRes = PowerManager.GetRoles(lamada).ToList();
return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
}
#endregion
#region 用戶管理
public JsonResult GetUsers(int limit, int offset, string username, string fullname)
{
var oLamadaExtention = new LamadaExtention();
if (!string.IsNullOrEmpty(username))
{
oLamadaExtention.GetExpression("USER_NAME", username, ExpressionType.Contains);
}
if (!string.IsNullOrEmpty(fullname))
{
oLamadaExtention.GetExpression("FULLNAME", fullname, ExpressionType.Contains);
}
var lamada = oLamadaExtention.GetLambda();
var lstRes = PowerManager.GetUsers(lamada).ToList();
return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
}
public object GetUserEdit(string strPostData)
{
var oUser = Newtonsoft.Json.JsonConvert.DeserializeObject(strPostData);
if (string.IsNullOrEmpty(oUser.USER_ID))
{
oUser.USER_ID = Guid.NewGuid().ToString();
oUser = PowerManager.AddUser(oUser);
}
else
{
PowerManager.UpdateUser(oUser);
}
return oUser;
}
public object DeleteUser(string strID)
{
PowerManager.DeleteUser(x => x.USER_ID == strID);
return new object();
}
#endregion
}
View頁面
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Styles.Render("~/Content/table-css")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Scripts.Render("~/bundles/bootstrap-table")
@RenderSection("Scripts", false)
</head>
<body>
@RenderBody()
</body>
</html>
@{
ViewBag.Title = "部門管理";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@Scripts.Render("~/bundles/PowerManage/DepartmentManage")
<div class="panel-body" style="padding-bottom:0px;">
<div class="panel panel-default">
<div class="panel-heading">查詢條件</div>
<div class="panel-body">
<div class="row">
<div class="col-md-4">
<label for="txt_search_departmentname" class="col-sm-4 control-label" style="margin-top:6px;">部門名稱</label>
<span class="col-sm-8">
<input type="text" class="form-control" id="txt_search_departmentname">
</span>
</div>
<div class="col-md-4">
<label for="txt_search_statu" class="col-sm-3 control-label" style="margin-top:6px;">狀態</label>
<span class="col-sm-8">
<input type="text" class="form-control" id="txt_search_statu">
</span>
</div>
<div class="col-md-4">
<button type="button" id="btn_query" class="btn btn-primary">查詢</button>
</div>
</div>
</div>
</div>
</div>
<div id="toolbar" class="btn-group">
<button id="btn_add" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
</button>
<button id="btn_edit" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改
</button>
<button id="btn_delete" type="button" class="btn btn-default">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>刪除
</button>
</div>
<table id="tb_departments"></table>
<form>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">新增</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="txt_departmentname">部門名稱</label>
<input type="text" name="txt_departmentname" class="form-control" id="txt_departmentname" placeholder="部門名稱">
</div>
<div class="form-group">
<label for="txt_parentdepartment">上級部門</label>
<input type="text" name="txt_parentdepartment" class="form-control" id="txt_parentdepartment" placeholder="上級部門">
</div>
<div class="form-group">
<label for="txt_departmentlevel">部門級別</label>
<input type="text" name="txt_departmentlevel" class="form-control" id="txt_departmentlevel" placeholder="部門級別">
</div>
<div class="form-group">
<label for="txt_statu">狀態</label>
<input type="text" name="txt_statu" class="form-control" id="txt_statu" placeholder="狀態">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>關閉</button>
<button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
</div>
</div>
</div>
</div>
</form>
JS代碼我們來看一個頁面就好了,其他頁面類似:
$(function () {
$('#tb_departments').bootstrapTable({
url: '/PowerManager/GetDepartments',
method: 'post',
toolbar: '#toolbar',
pagination: true,
queryParams: queryParams,
queryParamsType: "limit",
//ajaxOptions: { departmentname: "", statu: "" },
sidePagination: "server",
pageSize: 5,
pageList: [5, 25, 50, 100],
search: true,
strictSearch: true,
showColumns: true,
showRefresh: true,
minimumCountColumns: 2,
clickToSelect: true,
columns: [{
checkbox: true
}, {
field: 'DEPARTMENT_NAME',
title: '部門名稱'
}, {
field: 'PARENT_ID',
title: '上級部門'
}, {
field: 'DEPARTMENT_LEVEL',
title: '部門級別'
}, {
field: 'STATUS',
title: '狀態'
}, ],
onLoadSuccess: function (data) {
var odata = data;
}
});
var oButtonInit = new ButtonInit();
oButtonInit.Init();
});
function queryParams(params) { //配置參數
var temp = { //這里的鍵的名字和控制器的變量名必須一直,這邊改動,控制器也需要改成一樣的
limit: params.limit, //頁面大小
offset: params.offset, //頁碼
departmentname: $("#txt_search_departmentname").val(),
statu: $("#txt_search_statu").val()
};
return temp;
}
var ButtonInit = function () {
var oInit = new Object();
var postdata = {};
oInit.Init = function () {
$("#btn_add").click(function () {
$("#myModalLabel").text("新增");
$("#myModal").find(".form-control").val("");
$('#myModal').modal()
postdata.DEPARTMENT_ID = "";
});
$("#btn_edit").click(function () {
var arrselections = $("#tb_departments").bootstrapTable('getSelections');
if (arrselections.length > 1) {
//alert("只能選擇一行進行編輯");
$("#btn_alert").alert();
return;
}
if (arrselections.length <= 0) {
//alert("請先選擇需要編輯的行");
$("#btn_alert").alert()
return;
}
$("#myModalLabel").text("編輯");
$("#txt_departmentname").val(arrselections[0].DEPARTMENT_NAME);
$("#txt_parentdepartment").val(arrselections[0].PARENT_ID);
$("#txt_departmentlevel").val(arrselections[0].DEPARTMENT_LEVEL);
$("#txt_statu").val(arrselections[0].STATUS);
postdata.DEPARTMENT_ID = arrselections[0].DEPARTMENT_ID;
$('#myModal').modal();
});
$("#btn_delete").click(function () {
var arrselections = $("#tb_departments").bootstrapTable('getSelections');
if (arrselections.length <= 0) {
//alert("請先選擇需要編輯的行");
$("#btn_alert").alert()
return;
}
if (!confirm("確定要刪除選定的數據嗎?")) {
return;
}
$.ajax({
type: "post",
url: "/PowerManager/DeleteDept",
data: { strID: arrselections[0].DEPARTMENT_ID },
success: function (data, status) {
if (status == "success") {
alert("提交數據成功");
$("#tb_departments").bootstrapTable('refresh');
}
},
error: function () {
alert("error");
},
complete: function () {
//alert("complete");
}
});
});
$("#btn_submit").click(function () {
postdata.DEPARTMENT_NAME = $("#txt_departmentname").val();
postdata.PARENT_ID = $("#txt_parentdepartment").val();
postdata.DEPARTMENT_LEVEL = $("#txt_departmentlevel").val();
postdata.STATUS = $("#txt_statu").val();
$.ajax({
type: "post",
url: "/PowerManager/GetDepartmentEdit",
data: { strPostData: JSON.stringify(postdata) },
success: function (data, status) {
if (status == "success") {
alert("提交數據成功");
$("#tb_departments").bootstrapTable('refresh');
}
},
error: function () {
//alert("error");
},
complete: function () {
//alert("complete");
}
});
});
$("#btn_query").click(function () {
$("#tb_departments").bootstrapTable('refresh');
});
};
return oInit;
};
效果圖:



在做頁面數據更新的時候,博主又遇到一個問題:ObjectStateManager 中已存在具有同一鍵的對象。ObjectStateManager 無法跟蹤具有相同鍵的多個對象。在此還是記錄下解決方案:
在倉儲的公共實現類中將
public virtual IQueryable Entities
{
get { return UnitOfWork.context.Set(); }
}
改成
public virtual IQueryable Entities
{
get { return UnitOfWork.context.Set().AsNoTracking() as IQueryable; }
}
就可以了。
至此,從領域模型到Web前端的代碼基本完成,可能很多代碼并未完善,比如異常處理、數據驗證等。
DDD領域驅動設計初探系列文章: