标签 标签 标签
- 一句话的事儿:
前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码。之前的六篇完成了领域层、应用层、以及基础结构层的部分代码,这篇打算搭建下UI层的代码。
DDD领域驱动设计初探系列文章:
- C#进阶系列——DDD领域驱动设计初探(一):聚合
- C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)
- C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)
- C#进阶系列——DDD领域驱动设计初探(四):WCF搭建
- C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用
- C#进阶系列——DDD领域驱动设计初探(六):领域服务
C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建
一、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/
Bootstrap离线API二、代码示例
上篇完成了WCF的设计代码,但是具体的业务逻辑的代码还没有,我们先来实现具体业务的CURD代码。
1、WCF代码
1.1 WCF服务业务接口代码
/// <summary>/// 权限管理模块接口契约/// </summary>[ServiceContract][ServiceInterface]public interface IPowerManageWCFService{#region 用户管理[OperationContract]List<DTO_TB_USERS> 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<DTO_TB_DEPARTMENT> 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<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode);[OperationContract]DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole);#endregion#region 菜单管理[OperationContract]List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode);[OperationContract]DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu);#endregion}
1.2 WCF接口实现代码:
```csharp [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) { Expression<Func<DTO_TB_USERS, bool>> selector = null;if (expressionNode != null){selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>();}var lstRes = base.GetDtoByLamada<DTO_TB_USERS, TB_USERS>(userRepository, selector);return lstRes;
}
public DTO_TB_USERS AddUser(DTO_TB_USERS oUser) {
return base.AddDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
}
public bool DeleteUser(DTO_TB_USERS oUser) {
var bRes = false;try{base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);bRes = true;}catch{}return bRes;
}
public bool DeleteUserByLamada(ExpressionNode expressionNode) {
Expression<Func<DTO_TB_USERS, bool>> selector = null;if (expressionNode != null){selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>();}var bRes = false;try{base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, selector);bRes = true;}catch{}return bRes;
}
public bool UpdateUser(DTO_TB_USERS oUser) {
var bRes = false;try{base.UpdateDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);bRes = true;}catch{}return bRes;
}
endregion
region 部门管理
public List
GetDepartments(ExpressionNode expressionNode) { Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null;if (expressionNode != null){selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>();}return base.GetDtoByLamada<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector);
} public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept) {
return base.AddDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
}
public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept) {
var bRes = false;try{base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);bRes = true;}catch{}return bRes;
}
public bool DeleteDeptByLamada(ExpressionNode expressionNode) {
Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null;if (expressionNode != null){selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>();}var bRes = false;try{base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector);bRes = true;}catch{}return bRes;
}
public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept) {
var bRes = false;try{base.UpdateDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);bRes = true;}catch{}return bRes;
}
endregion
region 角色管理
public List
GetRoles(ExpressionNode expressionNode) { Expression<Func<DTO_TB_ROLE, bool>> selector = null;if (expressionNode != null){selector = expressionNode.ToExpression<Func<DTO_TB_ROLE, bool>>();}return base.GetDtoByLamada<DTO_TB_ROLE, TB_ROLE>(roleRepository, selector);
}
public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole) {
return base.AddDto<DTO_TB_ROLE, TB_ROLE>(roleRepository, oRole);
}
endregion
region 菜单管理
public List
GetMenus(ExpressionNode expressionNode) { Expression<Func<DTO_TB_MENU, bool>> selector = null;if (expressionNode != null){selector = expressionNode.ToExpression<Func<DTO_TB_MENU, bool>>();}return base.GetDtoByLamada<DTO_TB_MENU, TB_MENU>(menuRepository, selector);
}
public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu) {
return base.AddDto<DTO_TB_MENU, TB_MENU>(menuRepository, oMenu);
}
endregion
endregion
}
PowerManageWCFService
这里要说明一点,在通过lamada表达式查询的方法里面为什么不直接用Expression<Func<DTO_TB_USERS,bool>>这种类型,而要使用ExpressionNode这种类型的变量呢?<br />这是因为Expression不支持序列化,无法用于WCF数据的传递。ExpressionNode这个对象的使用需要添加Serialize.Linq这个dll的引用,还好有我们神奇的NuGet,让我们再也不用去网上找一大堆的dll了。<br /><br />我们公用的增删改查封装到了BaseService这个父类里面。<a name="BTkUW"></a>#### 1.3 BaseService代码```csharppublic class BaseService{#region Fieldsprivate bool bInitAutoMapper = false;#endregion#region Constructpublic BaseService(){//注册MEFRegisgter.regisgter().ComposeParts(this);}#endregion#region 查询/// <summary>/// 通用单表查询方法/// </summary>/// <typeparam name="DtoModel">DTOmodel</typeparam>/// <typeparam name="DomainModel">领域模型</typeparam>/// <param name="oRepository">需要传过来的仓储接口对象</param>/// <param name="selector">前端传过来的lamada表达式</param>/// <returns></returns>public List<DtoModel> GetDtoByLamada<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null)where DomainModel : AggregateRootwhere DtoModel : Dto_BaseModel{InitAutoMapper<DtoModel, DomainModel>();if (selector == null){var lstDomainModel = oRepository.Entities.ToList();return Mapper.Map<List<DomainModel>, List<DtoModel>>(lstDomainModel);}//得到从Web传过来和DTOModel相关的lamaba表达式的委托Func<DtoModel, bool> match = selector.Compile();//创建映射Expression的委托Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile();//得到领域Model相关的lamadaExpression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t));List<DomainModel> list = oRepository.Find(lamada).ToList();return Mapper.Map<List<DomainModel>, List<DtoModel>>(list);}#endregion#region 新增public DtoModel AddDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)where DomainModel : AggregateRootwhere DtoModel : Dto_BaseModel{InitAutoMapper<DtoModel, DomainModel>();var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);oRepository.Insert(oDomain);return Mapper.Map<DomainModel, DtoModel>(oDomain);}#endregion#region 删除public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)where DomainModel : AggregateRootwhere DtoModel : Dto_BaseModel{InitAutoMapper<DtoModel, DomainModel>();var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);return oRepository.Delete(oDomain);}public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null)where DomainModel : AggregateRootwhere DtoModel : Dto_BaseModel{InitAutoMapper<DtoModel, DomainModel>();if (selector == null){return 0;}//得到从Web传过来和DTOModel相关的lamaba表达式的委托Func<DtoModel, bool> match = selector.Compile();//创建映射Expression的委托Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile();//得到领域Model相关的lamadaExpression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t));return oRepository.Delete(lamada);}#endregion#region 更新public void UpdateDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)where DomainModel : AggregateRootwhere DtoModel : Dto_BaseModel{InitAutoMapper<DtoModel, DomainModel>();var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);oRepository.Update(oDomain);}#endregion#region Privateprivate void InitAutoMapper<DtoModel, DomainModel>(){var oType = Mapper.FindTypeMapFor<DtoModel, DomainModel>();if (oType==null){Mapper.CreateMap<DtoModel, DomainModel>();Mapper.CreateMap<DomainModel, DtoModel>();}}#endregion}BaseService
这个父类主要做了两件事:一是MEF的初始化;二是通用增删改查的实现。所有dto对象和领域model的映射都在这里统一管理。
2、UI层代码
UI层里面,为了更好分离代码,我们引入了接口编程的机制,引入了ESTM.Web.IBLL和ESTM.Web.BLL两个项目,如图:
为什么要有这么一个接口层?之前C#进阶系列——MEF实现设计上的“松耦合”(终结篇:面向接口编程)这篇已经做过介绍,对面向接口编程不了解的朋友可以看看。
2.1 ESTM.Web.IBLL代码
这个dll主要定义接口规则。
public interface IPowerManager{List<DTO_TB_USERS> GetUsers(Expression<Func<DTO_TB_USERS, bool>> selector = null);DTO_TB_USERS AddUser(DTO_TB_USERS oUser);bool DeleteUser(DTO_TB_USERS oUser);bool UpdateUser(DTO_TB_USERS oUser);bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null);List<DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null);DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept);bool DeleteDepartment(DTO_TB_DEPARTMENT oDept);bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null);bool UpdateDepartment(DTO_TB_DEPARTMENT oDept);List<DTO_TB_ROLE> GetRoles(Expression<Func<DTO_TB_ROLE, bool>> selector = null);List<DTO_TB_MENU> GetMenus(Expression<Func<DTO_TB_MENU, bool>> 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<DTO_TB_USERS> GetUsers(Expression<Func<Common.DtoModel.DTO_TB_USERS, bool>> selector = null){return oService.GetUsers(GetExpressionNode<DTO_TB_USERS>(selector));}public List<Common.DtoModel.DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<Common.DtoModel.DTO_TB_DEPARTMENT, bool>> selector = null){return oService.GetDepartments(GetExpressionNode<DTO_TB_DEPARTMENT>(selector));}public List<Common.DtoModel.DTO_TB_ROLE> GetRoles(Expression<Func<Common.DtoModel.DTO_TB_ROLE, bool>> selector = null){return oService.GetRoles(GetExpressionNode<DTO_TB_ROLE>(selector));}public List<Common.DtoModel.DTO_TB_MENU> GetMenus(Expression<Func<Common.DtoModel.DTO_TB_MENU, bool>> selector = null){return oService.GetMenus(GetExpressionNode<DTO_TB_MENU>(selector));}#endregion#region Privates//将lamada表达式转换为可用于WCF传递的ExpressionNode类型private ExpressionNode GetExpressionNode<Dto>(Expression<Func<Dto,bool>> selector){if (selector == null){return null;}ExpressionConverter expressionConverter = new ExpressionConverter();ExpressionNode expressionNode = expressionConverter.Convert(selector);return expressionNode;}#endregionpublic 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(Expression<Func<DTO_TB_USERS, bool>> 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(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null){if (selector == null){return false;}ExpressionConverter expressionConverter = new ExpressionConverter();ExpressionNode expressionNode = expressionConverter.Convert(selector);return oService.DeleteDeptByLamada(expressionNode);}}PowerManager : IPowerManager
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: PowerManagerpublic 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<DTO_TB_DEPARTMENT>();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<DTO_TB_DEPARTMENT>(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<DTO_TB_MENU>();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<DTO_TB_MENU>(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<DTO_TB_ROLE>();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<DTO_TB_USERS>();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<DTO_TB_USERS>(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}PowerManagerController
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>_Layout.cshtml
@{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>Department.cshtml
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;};DepartmentManage.js
效果图:


在做页面数据更新的时候,博主又遇到一个问题:ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。在此还是记录下解决方案:
在仓储的公共实现类中将
public virtual IQueryable<TEntity> Entities{get { return UnitOfWork.context.Set<TEntity>(); }}
改成
public virtual IQueryable<TEntity> Entities{get { return UnitOfWork.context.Set<TEntity>().AsNoTracking() as IQueryable<TEntity>; }}
就可以了。
至此,从领域模型到Web前端的代码基本完成,可能很多代码并未完善,比如异常处理、数据验证等。之前写过一篇CS版本的权限系统 系统设计——权限系统,很多朋友找我要过源码,那个时候可能代码都在工作的项目中,没办法抽离出来,在此表示抱歉。现在做了一个BS的,感觉BS比CS界面好看,在这里将源码分享出来,当然这里的代码肯定也不太全,很多没实现的功能还需要自己去实现,但是基本的架子搭起来了,有兴趣可以看看。源码下载
- 本文作者:GeekPower - Felix Sun
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!
