MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具
MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具集成Visual Studio 2013
MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具
经过一个多星期的努力总算完成了单表,多表关联(一对多,多对一)的增删改查的代码生成,基本上可以实现不用添加任何代码完成对数据表的操作。
下个阶段打算集成.net 4.5的认证和授权已经用户注册和角色管理
一旦有更好的方式我会把它集成到模板中实现自动生成。所以很希望得到大家的帮助。在这里我先抛砖引玉了。
asp.net MVC 5 Scaffolding多层架构代码生成向导开源项目(邀请你的参与)
Demo和所有源代码代码在 https://github.com/neozhu/MVC5-Scaffolder
先看一下我的Demo实例
实体类的结构
Order 与 OrderDetail 一对多,OrderDetail 与 Product 多对一,Order与Product则是多对多的关系。
实现的操作界面如下图
查询界面
功能:
1/新增操作 : 页面跳转到新增页面
2/删除操作 : 选择记录或单击行上的删除 弹出确认框 是否删除改记录
3/编辑操作 : 单击行上的编辑图标页面跳转到编辑页面
4/查询操作 : 在Search 文本框中输入关键字会根据后台每个字段的查询,选择需要显示的字段
5/Table功能 :字段显示勾选,分页显示,所有功能都是服务端实现
新增页面
功能:
布局:上部表头,下部的Tab为表体明细
一对多 :表体用table显示
多对一 :用Dropdownlist进行选择
表体明细的操作 :使用popup modal的方式操作
单击保存后,系统会自动合并表头表体一起提交到后台进行保存
编辑页面
功能:
加载数据:会根据主从关系把表头/表体的数据一次性加载
编辑数据:对表体明细的的操作类似新增页面,但对表体进行删除操作时会进行提示是否真的要删除后台数据。
保存数据:一次性提交所有表头/表体数据到后台进行操作。
上述这些功能完全可以代码生成 不需要做任何修改
项目结构
View层的代码
Index :查询Table List
Create :新增页面
Edit : 编辑页面
EditForm :Partial View内嵌在Create 和Edit页面中
_OrderDetailForm : pupup 子表维护表单页面
Create,和Edit页面通过Ajax Post 把数据提交到后台的Controller进行操作
代码如下
<script type="text/javascript"> var orderid = 0;
var ObjectState = "Added"; var $orderdetailstable = {};
$(document).ready(function () { $('form').submit(function () {
var token = $('[name=__RequestVerificationToken]').val();
var serializedForm = $(this).serialize();
var actionurl = $(this).attr('action'); var orderdetails = $orderdetailstable.bootstrapTable('getData'); var newitem = {
OrderDetails: orderdetails, Id: orderid,
Customer: $('#Customer', 'form').val(),
ShippingAddress: $('#ShippingAddress', 'form').val(),
OrderDate: $('#OrderDate', 'form').val(),
ObjectState: ObjectState
};
$.ajax({
url: actionurl,
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(newitem),
success: function (result) {
if (result.success) {
self.location = "/Orders/Index";
} else {
alert(result.err);
} },
error: function (result) {
console.log(result.statusText + result.responseText);
alert(result.statusText + result.responseText);
}
});
return false; });
});
</script>
通过Jquery 获取表头和表体数据 序列化成Json对象然后Post到后台
Controller层代码
这里就只贴Create方法的代码
public class OrdersController : Controller
{
//private StoreContext db = new StoreContext();
private readonly IOrderService _orderService;
private readonly IUnitOfWorkAsync _unitOfWork; public OrdersController(IOrderService orderService, IUnitOfWorkAsync unitOfWork)
{
_orderService = orderService;
_unitOfWork = unitOfWork;
} // GET: Orders/Index
public ActionResult Index()
{ var orders = _orderService.Queryable().AsQueryable();
return View(orders);
} // Get :Orders/PageList
// For Index View Boostrap-Table load data
[HttpGet]
public ActionResult PageList(int offset = 0, int limit = 10, string search = "", string sort = "", string order = "")
{
int totalCount = 0;
int pagenum = offset / limit + 1;
var orders = _orderService.Query(new OrderQuery().WithAnySearch(search)).OrderBy(n => n.OrderBy(sort, order)).SelectPage(pagenum, limit, out totalCount);
var rows = orders.Select(n => new { Id = n.Id, Customer = n.Customer, ShippingAddress = n.ShippingAddress, OrderDate = n.OrderDate }).ToList();
var pagelist = new { total = totalCount, rows = rows };
return Json(pagelist, JsonRequestBehavior.AllowGet);
} // GET: Orders/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = _orderService.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
} // GET: Orders/Create
public ActionResult Create()
{
return View();
} // POST: Orders/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "OrderDetails,Id,Customer,ShippingAddress,OrderDate")] Order order)
{
if (ModelState.IsValid)
{
order.ObjectState = ObjectState.Added;
foreach (var item in order.OrderDetails)
{
item.OrderId = order.Id;
item.ObjectState = ObjectState.Added;
}
_orderService.InsertOrUpdateGraph(order);
_unitOfWork.SaveChanges();
if (Request.IsAjaxRequest())
{
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
DisplaySuccessMessage("Has append a Order record");
return RedirectToAction("Index");
} if (Request.IsAjaxRequest())
{
var modelStateErrors = String.Join("", this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors.Select(n => n.ErrorMessage)));
return Json(new { success = false, err = modelStateErrors }, JsonRequestBehavior.AllowGet);
}
DisplayErrorMessage();
return View(order);
} // GET: Orders/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = _orderService.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
} // POST: Orders/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "OrderDetails,Id,Customer,ShippingAddress,OrderDate")] Order order)
{
if (ModelState.IsValid)
{
order.ObjectState = ObjectState.Modified;
foreach (var item in order.OrderDetails)
{
item.OrderId = order.Id;
//set ObjectState with conditions
if (item.Id <= 0)
item.ObjectState = ObjectState.Added;
else
item.ObjectState = ObjectState.Modified;
} _orderService.InsertOrUpdateGraph(order); _unitOfWork.SaveChanges();
if (Request.IsAjaxRequest())
{
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
DisplaySuccessMessage("Has update a Order record");
return RedirectToAction("Index");
}
if (Request.IsAjaxRequest())
{
var modelStateErrors = String.Join("", this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors.Select(n => n.ErrorMessage)));
return Json(new { success = false, err = modelStateErrors }, JsonRequestBehavior.AllowGet);
}
DisplayErrorMessage();
return View(order);
} // GET: Orders/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Order order = _orderService.Find(id);
if (order == null)
{
return HttpNotFound();
}
return View(order);
} // POST: Orders/Delete/5
[HttpPost, ActionName("Delete")]
//[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Order order = _orderService.Find(id);
_orderService.Delete(order);
_unitOfWork.SaveChanges();
if (Request.IsAjaxRequest())
{
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
DisplaySuccessMessage("Has delete a Order record");
return RedirectToAction("Index");
} // Get Detail Row By Id For Edit
// Get : Orders/EditOrderDetail/:id
[HttpGet]
public ActionResult EditOrderDetail(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var orderdetailRepository = _unitOfWork.Repository<OrderDetail>();
var orderdetail = orderdetailRepository.Find(id); var orderRepository = _unitOfWork.Repository<Order>();
var productRepository = _unitOfWork.Repository<Product>(); if (orderdetail == null)
{
ViewBag.OrderId = new SelectList(orderRepository.Queryable(), "Id", "Customer");
ViewBag.ProductId = new SelectList(productRepository.Queryable(), "Id", "Name"); //return HttpNotFound();
return PartialView("_OrderDetailEditForm", new OrderDetail());
}
else
{
ViewBag.OrderId = new SelectList(orderRepository.Queryable(), "Id", "Customer", orderdetail.OrderId);
ViewBag.ProductId = new SelectList(productRepository.Queryable(), "Id", "Name", orderdetail.ProductId); }
return PartialView("_OrderDetailEditForm", orderdetail); } // Get Create Row By Id For Edit
// Get : Orders/CreateOrderDetail
[HttpGet]
public ActionResult CreateOrderDetail()
{
var orderRepository = _unitOfWork.Repository<Order>();
ViewBag.OrderId = new SelectList(orderRepository.Queryable(), "Id", "Customer");
var productRepository = _unitOfWork.Repository<Product>();
ViewBag.ProductId = new SelectList(productRepository.Queryable(), "Id", "Name");
return PartialView("_OrderDetailEditForm"); } // Post Delete Detail Row By Id
// Get : Orders/DeleteOrderDetail/:id
[HttpPost, ActionName("DeleteOrderDetail")]
public ActionResult DeleteOrderDetailConfirmed(int id)
{
var orderdetailRepository = _unitOfWork.Repository<OrderDetail>();
orderdetailRepository.Delete(id);
_unitOfWork.SaveChanges();
if (Request.IsAjaxRequest())
{
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
DisplaySuccessMessage("Has delete a Order record");
return RedirectToAction("Index");
} // Get : Orders/GetOrderDetailsByOrderId/:id
[HttpGet]
public ActionResult GetOrderDetailsByOrderId(int id)
{
var orderdetails = _orderService.GetOrderDetailsByOrderId(id);
if (Request.IsAjaxRequest())
{
return Json(orderdetails.Select(n => new { OrderCustomer = n.Order.Customer, ProductName = n.Product.Name, Id = n.Id, ProductId = n.ProductId, Qty = n.Qty, Price = n.Price, Amount = n.Amount, OrderId = n.OrderId }), JsonRequestBehavior.AllowGet);
}
return View(orderdetails); } private void DisplaySuccessMessage(string msgText)
{
TempData["SuccessMessage"] = msgText;
} private void DisplayErrorMessage()
{
TempData["ErrorMessage"] = "Save changes was unsuccessful.";
} protected override void Dispose(bool disposing)
{
if (disposing)
{
//_unitOfWork.Dispose();
}
base.Dispose(disposing);
}
}
Popup Modal编辑子表数据代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
<script type= "text/javascript" > var currentrowindex = -1; function deleteOrderDetail(id) { var url = '@Url.Action("DeleteOrderDetail")' ; bootbox.dialog({ message: "Are you sure delete " + id, title: "Delete OrderDetail " , buttons: { Cancel: { label: "Cancel" , className: "btn-default" , callback: function () { } }, OK: { label: "OK" , className: "btn-success" , callback: function () { $.post(url, { id: id }, function (data) { $orderdetailstable.bootstrapTable( 'remove' , { field: 'Id' , values: [id] }); //console.log('remove' + row.Id); }); } } } }); } function orderdetailsrowindexFormatter(value, row, index) { return index + 1; } function orderdetailsactionFormatter(value, row, index) { return [ '<a class="edit" id="orderdetailsedit" href="javascript:void(0)" title="Add">' , '<i class="glyphicon glyphicon-edit"></i>' , '</a> ' , ' <a class="remove" id="orderdetailsremove" href="javascript:void(0)" title="Remove">' , '<i class="glyphicon glyphicon-remove"></i>' , '</a>' ]. join ( '' ); } window.actionEvents = { 'click #orderdetailsedit' : function (e, value, row, index) { currentrowindex = index; var url = "/Orders/EditOrderDetail" $. get (url + '/' + row.Id, function (data) { $( '#orderdetailformModal-body' ).html(data); if (row.Id > 0) { //var id = $('#Id','#orderdetailformModal-body'); //id.val(row.Id); //var productid = $('#ProductId','#orderdetailformModal-body'); //productid.val(row.ProductId); //var qty = $('#Qty','#orderdetailformModal-body'); //qty.val(row.Qty); //var price = $('#Price','#orderdetailformModal-body'); //price.val(row.Price); //var amount = $('#Amount','#orderdetailformModal-body'); //amount.val(row.Amount); //var orderid = $('#OrderId','#orderdetailformModal-body'); //orderid.val(row.OrderId); } else { var id = $( '#Id' , '#orderdetailformModal-body' ); id.val(row.Id); var productid = $( '#ProductId' , '#orderdetailformModal-body' ); productid.val(row.ProductId); var qty = $( '#Qty' , '#orderdetailformModal-body' ); qty.val(row.Qty); var price = $( '#Price' , '#orderdetailformModal-body' ); price.val(row.Price); var amount = $( '#Amount' , '#orderdetailformModal-body' ); amount.val(row.Amount); var orderid = $( '#OrderId' , '#orderdetailformModal-body' ); orderid.val(row.OrderId); } $( '#orderdetailformModal' ).modal( 'toggle' ); }); }, 'click #orderdetailsremove' : function (e, value, row, index) { if (row.Id > 0) { deleteOrderDetail(row.Id); } else { $orderdetailstable.bootstrapTable( 'remove' , { field: '$index' , values: [index] }); } } }; $(function () { $orderdetailstable = $( '#orderdetails-table' ).bootstrapTable({ data: [] }); if (ObjectState == "Modified" ) { orderid = $( '#Id' ).val(); var url = '/Orders/GetOrderDetailsByOrderId/' + orderid; $. get (url, function (data) { //console.log(data); $orderdetailstable.bootstrapTable( 'load' , data) }) } $( '#addorderdetailsbutton' ). on ( 'click' , function (e) { if ($( "form" ).valid()) { currentrowindex = -1; var url = "/Orders/CreateOrderDetail" $. get (url, function (data) { //console.log(data); var index = -1; $( '#orderdetailformModal-body' ).html(data); $( '#Id' , '#orderdetailformModal-body' ).val(0); $( '#OrderId' , '#orderdetailformModal-body' ).val(orderid); $( '#orderdetailformModal' ).modal( 'toggle' ); }); } e.preventDefault(); //Return false regardless of validation to stop form submitting //prior to ajax doing its thing return false ; }) $( '#orderdetailconfirmbutton' ). on ( 'click' , function (e) { $( "form" ).removeData( "validator" ); $( "form" ).removeData( "unobtrusiveValidation" ); $.validator.unobtrusive.parse( "form" ); if (!$( 'form' ).valid()) { e.preventDefault(); return false ; } var ordercustomer = $( '#OrderId :selected' , '#orderdetailformModal-body' ).text(); var productname = $( '#ProductId :selected' , '#orderdetailformModal-body' ).text(); var id = $( '#Id' , '#orderdetailformModal-body' ).val(); var productid = $( '#ProductId :selected' , '#orderdetailformModal-body' ).val(); var qty = $( '#Qty' , '#orderdetailformModal-body' ).val(); var price = $( '#Price' , '#orderdetailformModal-body' ).val(); var amount = $( '#Amount' , '#orderdetailformModal-body' ).val(); var orderid = $( '#OrderId :selected' , '#orderdetailformModal-body' ).val(); var orderdetail = { OrderCustomer: ordercustomer, ProductName: productname, Id: id, ProductId: productid, Qty: qty, Price: price, Amount: amount, OrderId: orderid, ObjectState: 'Added' } if (currentrowindex == '-1' ) { $orderdetailstable.bootstrapTable( 'append' , orderdetail); } else { $orderdetailstable.bootstrapTable( 'updateRow' , { index: currentrowindex, row: orderdetail }); } $( '#orderdetailformModal' ).modal( 'toggle' ); }); }); </script> |
所有代码都是根据Entity 类型 和字段名进行生成,理论上针对业务系统都可以模板化,只要模式定下来什么代码都可以生成。
转自 http://www.cnblogs.com/neozhu/p/4322939.html
MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具的更多相关文章
- MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具集成Visual Studio 2013
MVC 5 Scaffolder + EntityFramework+UnitOfWork Pattern 代码生成工具 经过一个多星期的努力总算完成了单表,多表关联(一对多,多对一)的增删改查的代码 ...
- RUF MVC5 Repositories Framework Generator代码生成工具介绍和使用
RUF MVC5 Repositories Framework Generator代码生成工具介绍和使用 功能介绍 这个项目经过了大半年的持续更新到目前的阶段基本稳定 所有源代码都是开源的,在gith ...
- Asp.net Webform 使用Repository模式实现CRUD操作代码生成工具
Asp.net Webform 使用Repository模式实现CRUD操作代码生成工具 介绍 该工具是通过一个github上的开源项目修改的原始作者https://github.com/Supere ...
- C# 代码生成工具 Millennials
Millennials 是一个可定制的 C# 代码生成工具,支持 MVC 和三层架构.ADO.NET.Nhibernate 和 LINQ. 项目主页:http://www.open-open.com/ ...
- Map工具系列-01-Map代码生成工具说明
所有cs端工具集成了一个工具面板 -打开(IE) Map工具系列-01-Map代码生成工具说明 Map工具系列-02-数据迁移工具使用说明 Map工具系列-03-代码生成BySQl工具使用说明 Map ...
- mybatis实战教程(mybatis in action)之九:mybatis 代码生成工具的使用
mybatis 应用程序,需要大量的配置文件,对于一个成百上千的数据库表来说,完全手工配置,这是一个很恐怖的工作量. 所以mybatis 官方也推出了一个mybatis代码生成工具的jar包. 今天花 ...
- 第二章 Mybatis代码生成工具
1.mybatis-generator作用 1).生成pojo 与 数据库结构对应 2).如果有主键,能匹配主键 3).如果没有主键,可以用其他字段去匹配 4).动态select,update,del ...
- 【C#】Excel做的数据表、SQLParameter代码生成工具
转载请注明出处http://www.cnblogs.com/Vulpers/ 做了一个小的代码生成工具,用于新建数据表时能够快速生成一些重复性很高的代码,目前仅支持SqlServer数据库及C#语言, ...
- 代码生成工具Database2Sharp中增加视图的代码生成以及主从表界面生成功能
在代码生成工具的各种功能规划中,我们一向以客户的需求作为驱动,因此也会根据需要增加一些特殊的功能或者处理.在实际的开发中,虽然我们一般以具体的表进行具体业务开发,但是有些客户提出有时候视图开发也是很常 ...
随机推荐
- 【BZOJ5304】[HAOI2018]字串覆盖(后缀数组,主席树,倍增)
[BZOJ5304][HAOI2018]字串覆盖(后缀数组,主席树,倍增) 题面 BZOJ 洛谷 题解 贪心的想法是从左往右,能选就选.这个显然是正确的. 题目的数据范围很好的说明了要对于询问分开进行 ...
- linux(fedora) 第三课
树形打印所有进程名:pstree pstree | grep pstree -A2 -B2(查看pstree前后两行) NI的值[-20,20) nice(改变NI的值):改变程序优先级 nice - ...
- Markdown基础(内含:锚点使用,使用HTML,新页面跳转,目录生成)
Github样式显示参考:点我 之前说过用word写文章,这次说说Markdown写文章(推荐) 逆天推荐使用VSCode编写 装这个插件写作更方便: 内含:锚点使用,使用HTML,新页面跳转,目录生 ...
- react-redux单元测试(基于react-addons-test-utils,mocha)
今天补上上次新闻客户端欠下的单元测试.新闻客户端github地址:点我,接上篇博客. 本次单元测试用到了单元测试比较流行的测试框架mocha,用到的是expect断言库,和react官方的测试插件:r ...
- Java,mysql String与date类型转换
String 与 date类型转换 字符串转换成日期类型: SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");//小写 ...
- Spring Cloud Vault介绍
https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247484838&idx=1&sn=6439ed96133dde ...
- [CTSC2018]暴力写挂——边分树合并
[CTSC2018]暴力写挂 题面不错 给定两棵树,两点“距离”定义为:二者深度相加,减去两棵树上的LCA的深度(深度指到根节点的距离) 求最大的距离. 解决多棵树的问题就是降维了. 经典的做法是边分 ...
- A1099. Build A Binary Search Tree
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following propertie ...
- [bzoj1692][队列变换]
题目链接 思路 首先肯定想到贪心,从队尾和队首取更小的那个. 但是如果遇到队尾和队首一样大的情况呢,总不能再挨个往前比较.所以就把整个字符串倒过来再挂到现在字符串的后面,也就是把当前字符串对称过去.然 ...
- JS验证身份证
话不多说,直接看代码 JS部分 /** * 身份证15位编码规则:dddddd yymmdd xx p * dddddd:地区码 * yymmdd: 出生年月日 * xx: 顺序类编码,无法确定 * ...