ASP.NET MVC 5 SmartCode Scaffolding是集成在Visual Studio.Net開發工具中一個ASP.NET MVC Web應用程序代碼生成框架,使用SmartCode Scaffolding能夠快速添加一整套View,Controller,Model,Service能夠運行的交互式代碼。減小程序員在系統開發過程當中編寫重複的代碼行數(估計能夠減小80%代碼Coding),同時有助於團隊成員遵循統一的架構和規範進行開發,就算沒有接觸過MVC的程序員也能快速的進行團隊開發。大大減小對基礎功能的debug的時間,提升軟件項目的開發效率。javascript
SmartCode Scaffolding是自定義擴展Visual Studio.Net ASP.NET Scaffolding而且實現了更多功能和生成更多的標準代碼。很是適合快速原型法的開發過程。css
該項目從2014年一直默默的在作版本更新和持續完善,從最先Visual Sutdio.Net 2013到最新2017。而且徹底開源 GITHUB SmartCode Scaffolding
個人聯繫方式 QQ:28440117,email:new163@163.com,微信:neostwitter
個人主頁:https://neozhu.github.io/WebSite/index.htmlhtml
須要要配合Demo中WebApp 項目來生成代碼,由於其中引用了大量的css和html模板java
參考EntityFramewrok Code-First規範定義,定義的越規範,信息越多對後面的生成的代碼就越完善。git
下面代碼定義一個Order,OrderDetail,一對多的關係,在建立Order類的Controller時會在controller,View,會根據關聯的實體生成相應的代碼,程序員
好比EditView,會同時生成對錶頭Order form表單的操做和明細表OrderDetail的datagrid操做。
定義OrderDetail中引用了Product,多對一的關係。會在View部分生成Combox控件或DropdownList的控件和Controller層的查詢方法。github
//定義字段描述信息,字段長度,基本驗證規則 public partial class Order:Entity { public Order() { OrderDetails = new HashSet<OrderDetail>(); } [Key] public int Id { get; set; } [Required] [Display(Name ="客戶名稱",Description ="訂單所屬的客戶",Order =1)] [MaxLength(30)] public string Customer { get; set; } [Required] [Display(Name = "發貨地址", Description = "發貨地址", Order = 2)] [MaxLength(200)] public string ShippingAddress { get; set; } [Display(Name = "訂單日期", Description = "訂單日期默認當天", Order = 3)] public DateTime OrderDate { get; set; } //關聯訂單明細 1-* public virtual ICollection<OrderDetail> OrderDetails { get; set; } } public partial class OrderDetail:Entity { [Key] public int Id { get; set; } [Required(ErrorMessage = "必選")] [Display(Name ="商品", Description ="商品",Order =2)] public int ProductId { get; set; } [ForeignKey("ProductId")] [Display(Name = "商品", Description = "商品", Order = 3)] public Product Product { get; set; } [Required(ErrorMessage="必填")] [Range(1,9999)] [Display(Name = "數量", Description = "需求數量", Order = 4)] public int Qty { get; set; } [Required(ErrorMessage = "必填")] [Range(1, 9999)] [Display(Name = "單價", Description = "單價", Order = 5)] public decimal Price { get; set; } [Required(ErrorMessage = "必填")] [Range(1, 9999)] [Display(Name = "金額", Description = "金額(數量x單價)", Order = 6)] public decimal Amount { get; set; } [Display(Name = "訂單號", Description = "訂單號", Order = 1)] public int OrderId { get; set; } //關聯訂單表頭 [ForeignKey("OrderId")] [Display(Name = "訂單號", Description = "訂單號", Order = 1)] public Order Order { get; set; } }
添加controllerjson
Controllers\OrdersController.cs /* MVC控制類 */ Repositories\Orders\OrderQuery.cs /* 定義與業務邏輯相關查詢好比分頁帥選,外鍵/主鍵查詢 */ Repositories\Orders\OrderRepository.cs /* Repository模式 */ Services\Orders\IOrderService.cs /* 具體的業務邏輯接口 */ Services\Orders\OrderService.cs /* 具體的業務邏輯實現 */ Views\Orders\Index.cshtml /* 訂單信息DataGrid包括查詢/新增/刪除/修改/導入/導出等功能 */ Views\Orders\_PopupDetailFormView.cshtml /* 訂單信息彈出編輯框 */ Views\Orders\Create.cshtml /* 訂單信息新增操做頁面 */ Views\Orders\Edit.cshtml /* 訂單信息編輯操做頁面 */ Views\Orders\EditForm.cshtml /* 訂單信息編輯表單 */
var entityname = "Order"; //下載Excel導入模板 function downloadtemplate() { //TODO: 修改下載模板的路徑 var url = "/ExcelTemplate/Order.xlsx"; $.fileDownload(url) .fail(function() { $.messager.alert("錯誤", "沒有找到模板文件! {" + url + "}"); }); } //打開Excel上傳導入 function importexcel() { $("#importwindow").window("open"); } //執行Excel處處下載 function exportexcel() { var filterRules = JSON.stringify($dg.datagrid("options").filterRules); //console.log(filterRules); $.messager.progress({ title: "正在執行導出!" }); var formData = new FormData(); formData.append("filterRules", filterRules); formData.append("sort", "Id"); formData.append("order", "asc"); $.postDownload("/Orders/ExportExcel", formData, function(fileName) { $.messager.progress("close"); console.log(fileName); }) } //顯示幫助信息 function dohelp() { } //easyui datagrid 增刪改查操做 var $dg = $("#orders_datagrid").datagrid({ rownumbers: true, checkOnSelect: true, selectOnCheck: true, idField: 'Id', sortName: 'Id', sortOrder: 'desc', remoteFilter: true, singleSelect: true, toolbar: '#orders_toolbar', url: '/Orders/GetData', method: 'get', onClickCell: onClickCell, pagination: true, striped: true, columns: [ [ /*{ field: 'ck', checkbox: true },*/ { field: '_operate1', title: '操做', width: 120, sortable: false, resizable: true, formatter: showdetailsformatter }, /*{field:'Id',width:80 ,sortable:true,resizable:true }*/ { field: 'Customer', title: '@Html.DisplayNameFor(model => model.Customer)', width: 140, editor: { type: 'textbox', options: { prompt: '客戶名稱', required: true, validType: 'length[0,30]' } }, sortable: true, resizable: true }, { field: 'ShippingAddress', title: '@Html.DisplayNameFor(model => model.ShippingAddress)', width: 140, editor: { type: 'textbox', options: { prompt: '發貨地址', required: true, validType: 'length[0,200]' } }, sortable: true, resizable: true }, { field: 'OrderDate', title: '@Html.DisplayNameFor(model => model.OrderDate)', width: 160, align: 'right', editor: { type: 'datebox', options: { prompt: '訂單日期', required: true } }, sortable: true, resizable: true, formatter: dateformatter }, ] ] }); var editIndex = undefined; function reload() { if (endEditing()) { $dg.datagrid("reload"); } } function endEditing() { if (editIndex == undefined) { return true } if ($dg.datagrid("validateRow", editIndex)) { $dg.datagrid("endEdit", editIndex); editIndex = undefined; return true; } else { return false; } } function onClickCell(index, field) { var _operates = ["_operate1", "_operate2", "_operate3", "ck"] if ($.inArray(field, _operates) >= 0) { return; } if (editIndex != index) { if (endEditing()) { $dg.datagrid("selectRow", index) .datagrid("beginEdit", index); editIndex = index; var ed = $dg.datagrid("getEditor", { index: index, field: field }); if (ed) { ($(ed.target).data("textbox") ? $(ed.target).textbox("textbox") : $(ed.target)).focus(); } } else { $dg.datagrid("selectRow", editIndex); } } } function append() { if (endEditing()) { //$dg.datagrid("appendRow", { Status: 0 }); //editIndex = $dg.datagrid("getRows").length - 1; $dg.datagrid("insertRow", { index: 0, row: {} }); editIndex = 0; $dg.datagrid("selectRow", editIndex) .datagrid("beginEdit", editIndex); } } function removeit() { if (editIndex == undefined) { return } $dg.datagrid("cancelEdit", editIndex) .datagrid("deleteRow", editIndex); editIndex = undefined; } function accept() { if (endEditing()) { if ($dg.datagrid("getChanges").length) { var inserted = $dg.datagrid("getChanges", "inserted"); var deleted = $dg.datagrid("getChanges", "deleted"); var updated = $dg.datagrid("getChanges", "updated"); var effectRow = new Object(); if (inserted.length) { effectRow.inserted = inserted; } if (deleted.length) { effectRow.deleted = deleted; } if (updated.length) { effectRow.updated = updated; } //console.log(JSON.stringify(effectRow)); $.post("/Orders/SaveData", effectRow, function(response) { //console.log(response); if (response.Success) { $.messager.alert("提示", "提交成功!"); $dg.datagrid("acceptChanges"); $dg.datagrid("reload"); } }, "json").fail(function(response) { //console.log(response); $.messager.alert("錯誤", "提交錯誤了!", "error"); //$dg.datagrid("reload"); }); } //$dg.datagrid("acceptChanges"); } } function reject() { $dg.datagrid("rejectChanges"); editIndex = undefined; } function getChanges() { var rows = $dg.datagrid("getChanges"); alert(rows.length + " rows are changed!"); } //datagrid 開啓篩選功能 $(function() { $dg.datagrid("enableFilter", [ { field: "Id", type: "numberbox", op: ['equal', 'notequal', 'less', 'lessorequal', 'greater', 'greaterorequal'] }, { field: "OrderDate", type: "dateRange", options: { onChange: function(value) { $dg.datagrid("addFilterRule", { field: "OrderDate", op: "between", value: value }); $dg.datagrid("doFilter"); } } }, ]); }) //----------------------------------------------------- //datagrid onSelect //----------------------------------------------------- function showdetailsformatter(value, row, index) { return '<a onclick="showDetailsWindow(' + row.Id + ')" class="easyui-linkbutton" href="javascript:void(0)">查看明細</a>'; } //彈出明細信息 function showDetailsWindow(id) { //console.log(index, row); $.getJSON('/Orders/PopupEdit/' + id, function(data, status, xhr) { //console.log(data); $('#detailswindow').window('open'); loadData(id, data); }); }
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 [OutputCache(Duration = 360, VaryByParam = "none")] public ActionResult Index() { return View(); } // Get :Orders/PageList // For Index View Boostrap-Table load data [HttpGet] public async Task<ActionResult> GetData(int page = 1, int rows = 10, string sort = "Id", string order = "asc", string filterRules = "") { var filters = JsonConvert.DeserializeObject<IEnumerable<filterRule>>(filterRules); var totalCount = 0; //int pagenum = offset / limit +1; var orders = await _orderService .Query(new OrderQuery().Withfilter(filters)) .OrderBy(n => n.OrderBy(sort, order)) .SelectPageAsync(page, rows, out totalCount); var datarows = orders.Select(n => new { Id = n.Id, Customer = n.Customer, ShippingAddress = n.ShippingAddress, OrderDate = n.OrderDate }).ToList(); var pagelist = new { total = totalCount, rows = datarows }; return Json(pagelist, JsonRequestBehavior.AllowGet); } [HttpPost] public async Task<ActionResult> SaveData(OrderChangeViewModel orders) { if (orders.updated != null) { foreach (var item in orders.updated) { _orderService.Update(item); } } if (orders.deleted != null) { foreach (var item in orders.deleted) { _orderService.Delete(item); } } if (orders.inserted != null) { foreach (var item in orders.inserted) { _orderService.Insert(item); } } await _unitOfWork.SaveChangesAsync(); return Json(new { Success = true }, JsonRequestBehavior.AllowGet); } //[OutputCache(Duration = 360, VaryByParam = "none")] public async Task<ActionResult> GetOrders(string q = "") { var orderRepository = _unitOfWork.RepositoryAsync<Order>(); var data = await orderRepository.Queryable().Where(n => n.Customer.Contains(q)).ToListAsync(); var rows = data.Select(n => new { Id = n.Id, Customer = n.Customer }); return Json(rows, JsonRequestBehavior.AllowGet); } //[OutputCache(Duration = 360, VaryByParam = "none")] public async Task<ActionResult> GetProducts(string q = "") { var productRepository = _unitOfWork.RepositoryAsync<Product>(); var data = await productRepository.Queryable().Where(n => n.Name.Contains(q)).ToListAsync(); var rows = data.Select(n => new { Id = n.Id, Name = n.Name }); return Json(rows, JsonRequestBehavior.AllowGet); } // GET: Orders/Details/5 public async Task<ActionResult> Details(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var order = await _orderService.FindAsync(id); if (order == null) { return HttpNotFound(); } return View(order); } // GET: Orders/Create public ActionResult Create() { var order = new Order(); //set default value return View(order); } // 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 async Task<ActionResult> Create([Bind(Include = "OrderDetails,Id,Customer,ShippingAddress,OrderDate,CreatedDate,CreatedBy,LastModifiedDate,LastModifiedBy")] 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); await _unitOfWork.SaveChangesAsync(); if (Request.IsAjaxRequest()) { return Json(new { success = true }, JsonRequestBehavior.AllowGet); } DisplaySuccessMessage("Has append a Order record"); return RedirectToAction("Index"); } else { var modelStateErrors = String.Join("", this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors.Select(n => n.ErrorMessage))); if (Request.IsAjaxRequest()) { return Json(new { success = false, err = modelStateErrors }, JsonRequestBehavior.AllowGet); } DisplayErrorMessage(modelStateErrors); } return View(order); } // GET: Orders/PopupEdit/5 [OutputCache(Duration = 360, VaryByParam = "id")] public async Task<ActionResult> PopupEdit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var order = await _orderService.FindAsync(id); return Json(order, JsonRequestBehavior.AllowGet); } // GET: Orders/Edit/5 public async Task<ActionResult> Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var order = await _orderService.FindAsync(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 async Task<ActionResult> Edit([Bind(Include = "OrderDetails,Id,Customer,ShippingAddress,OrderDate,CreatedDate,CreatedBy,LastModifiedDate,LastModifiedBy")] 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); await _unitOfWork.SaveChangesAsync(); if (Request.IsAjaxRequest()) { return Json(new { success = true }, JsonRequestBehavior.AllowGet); } DisplaySuccessMessage("Has update a Order record"); return RedirectToAction("Index"); } else { var modelStateErrors = String.Join("", this.ModelState.Keys.SelectMany(key => this.ModelState[key].Errors.Select(n => n.ErrorMessage))); if (Request.IsAjaxRequest()) { return Json(new { success = false, err = modelStateErrors }, JsonRequestBehavior.AllowGet); } DisplayErrorMessage(modelStateErrors); } return View(order); } // GET: Orders/Delete/5 public async Task<ActionResult> Delete(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var order = await _orderService.FindAsync(id); if (order == null) { return HttpNotFound(); } return View(order); } // POST: Orders/Delete/5 [HttpPost, ActionName("Delete")] //[ValidateAntiForgeryToken] public async Task<ActionResult> DeleteConfirmed(int id) { var order = await _orderService.FindAsync(id); _orderService.Delete(order); await _unitOfWork.SaveChangesAsync(); 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 async Task<ActionResult> EditOrderDetail(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var orderdetailRepository = _unitOfWork.RepositoryAsync<OrderDetail>(); var orderdetail = await orderdetailRepository.FindAsync(id); var orderRepository = _unitOfWork.RepositoryAsync<Order>(); var productRepository = _unitOfWork.RepositoryAsync<Product>(); if (orderdetail == null) { ViewBag.OrderId = new SelectList(await orderRepository.Queryable().ToListAsync(), "Id", "Customer"); ViewBag.ProductId = new SelectList(await productRepository.Queryable().ToListAsync(), "Id", "Name"); //return HttpNotFound(); return PartialView("_OrderDetailEditForm", new OrderDetail()); } else { ViewBag.OrderId = new SelectList(await orderRepository.Queryable().ToListAsync(), "Id", "Customer", orderdetail.OrderId); ViewBag.ProductId = new SelectList(await productRepository.Queryable().ToListAsync(), "Id", "Name", orderdetail.ProductId); } return PartialView("_OrderDetailEditForm", orderdetail); } // Get Create Row By Id For Edit // Get : Orders/CreateOrderDetail [HttpGet] public async Task<ActionResult> CreateOrderDetail() { var orderRepository = _unitOfWork.RepositoryAsync<Order>(); ViewBag.OrderId = new SelectList(await orderRepository.Queryable().ToListAsync(), "Id", "Customer"); var productRepository = _unitOfWork.RepositoryAsync<Product>(); ViewBag.ProductId = new SelectList(await productRepository.Queryable().ToListAsync(), "Id", "Name"); return PartialView("_OrderDetailEditForm"); } // Post Delete Detail Row By Id // Get : Orders/DeleteOrderDetail/:id [HttpPost, ActionName("DeleteOrderDetail")] public async Task<ActionResult> DeleteOrderDetailConfirmed(int id) { var orderdetailRepository = _unitOfWork.RepositoryAsync<OrderDetail>(); orderdetailRepository.Delete(id); await _unitOfWork.SaveChangesAsync(); 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 async Task<ActionResult> GetOrderDetailsByOrderId(int id) { var orderdetails = _orderService.GetOrderDetailsByOrderId(id); if (Request.IsAjaxRequest()) { var data = await orderdetails.AsQueryable().ToListAsync(); var rows = data.Select(n => new { OrderCustomer = (n.Order == null ? "" : n.Order.Customer), ProductName = (n.Product == null ? "" : n.Product.Name), Id = n.Id, ProductId = n.ProductId, Qty = n.Qty, Price = n.Price, Amount = n.Amount, OrderId = n.OrderId }); return Json(rows, JsonRequestBehavior.AllowGet); } return View(orderdetails); } //導出Excel [HttpPost] public ActionResult ExportExcel(string filterRules = "", string sort = "Id", string order = "asc") { var fileName = "orders_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx"; var stream = _orderService.ExportExcel(filterRules, sort, order); return File(stream, "application/vnd.ms-excel", fileName); } private void DisplaySuccessMessage(string msgText) { TempData["SuccessMessage"] = msgText; } private void DisplayErrorMessage(string msgText) { TempData["ErrorMessage"] = msgText; } protected override void Dispose(bool disposing) { if (disposing) { _unitOfWork.Dispose(); } base.Dispose(disposing); } }
/// <summary>Registers the type mappings with the Unity container.</summary> /// <param name="container">The unity container to configure.</param> /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks> public static void RegisterTypes(IUnityContainer container) { container.RegisterType<IRepositoryAsync<Order>, Repository<Order>>(); container.RegisterType<IOrderService, OrderService>(); container.RegisterType<IRepositoryAsync<OrderDetail>, Repository<OrderDetail>>(); container.RegisterType<IOrderDetailService, OrderDetailService>(); }
以上功能一鍵生成帶帶主從表關聯的多表同時操做的頁面功能和後臺代碼,包括必填,長度等輸入校驗規則服務器
即時聊天功能
系統帳號管理
菜單導航受權
Excel導入導出配置
枚舉值維護
系統日誌
消息通知微信
主要組件
"EntityFramework" version="6.2.0" 支持Oracle,MySql,Sql Server,PostgreSQL,SQLite,Sybase等
供應鏈協同平臺
MES系統
承接企業內部業務系統開發,組建企業私有云,虛擬化集羣服務器部署。
承接BizTalk B2B/EAI/EDI/AS/RosettaNet 開發工做
若是這個項目對您有用,咱們歡迎各方任何形式的捐助,也包括參與到項目代碼更新或意見反饋中來。謝謝!
資金捐助:
個人博客即將搬運同步至騰訊雲+社區,邀請你們一同入駐:https://cloud.tencent.com/developer/support-plan