前言:在兩年前(最初發布時間:2013年1月9日(csdn),當前文章時間2015年11月10日),項目組推出了基於Dapper,Mvc和WebApi的快速開發框架,隨着后續Slickflow產品的實踐和應用,今再次對SlickOne項目做以回顧和總結。其目的是精簡,持續改進,保持重構,讓開發人員了解到最新的變化,尤其是全棧開發人員做以參考。
兩年之前的博客文章可以查閱(最初發布時間:2013年1月9日):
http://blog.csdn.net/besley/article/details/8479943
1. 新版本變化綜述:
1) Dapper部分的變化:
Dapper本身有支持對數據庫底層接口,此次主要是增加了Oracle和MySQL數據庫的接口,也修改了Dapper里面的SqlMapper文件。
2) SlickOne.Data 數據訪問
在泛型封裝的基礎上,提供了列表分頁,新增主鍵ID返回,根據多ID值查詢返回列表,新增查詢功能的存儲過程等接口。
3) Mvc/WebApi
將兩個類型的項目動態庫文件整合在一個Web項目里面,同時響應頁面請求和Api請求。
4) Web前端
由JQueryUI 轉換到 Bootstrap框架,核心組件SlickGrid 轉換為Bootstrap樣式。
2. 框架設計
1) 數據訪問Repository泛型類
Repository泛型類,徹底實現數據快速訪問,不用重復編寫不同實體的通用基本方法;而且此泛型類的存在也用以支持Dapper,EF,Heibernate等各種數據訪問框架,考慮到不同用戶的技術儲備,只要去實現IRepository的接口方法就可以繼續使用自己喜歡的框架。

2) 基於簡單實體訪問
簡單實體,原始來源為數據庫表的對應實體,而且並限定為只包含屬性字段。在早期版本區分了數據實體和業務實體,有AutoMapper的轉換工具,在新版本里面,不再強調業務實體,而是統一命名為簡單實體,始終根據簡單實體做業務功能開發,做數據的存儲和讀取。
3) 接口定義優先策略
接口方法更加側重於業務過程的定義。基本方法如新增,編輯和刪除可以直接快速調用Repository里的泛型方法,不再默認自動生成Partial文件去維護,包括Interface, Service類和ApiController類都不再生成Partial類文件。
4) WebApi 接口封裝
消息體引用ResponseResult泛型類,包括狀態(Status),消息(Message)和實體(Entity)關鍵屬性。ResponseResult類用於服務端到前端的數據和消息封裝,消息內容格式是JSON數據格式。
5) Javascript模板引擎
采用前端Javascript模板引擎,解析WebApi傳遞回的JSON對象,做前端界面展現。模板引擎可以采用HandlebarsJS或DustJS。也可以選擇其它模板引擎。
6) Bootstrap
前端框架過渡到Bootstrap框架,相應的控件,如SlickGrid和ZTree等控件都可以找到對應Bootstrap的樣式版本。
3. 解決方案結構圖示

4. 項目代碼實例
1) 實體對象
/// <summary>
/// 產品實體對象
/// </summary>
[Table("PrdProduct")]
public class ProductEntity
{
public int ID { get; set; }
public string ProductName { get; set; }
public string ProductCode { get; set; }
public string ProductType { get; set; }
public Nullable<decimal> UnitPrice { get; set; }
public string Notes { get; set; }
}
2) 接口定義
/// <summary>
/// 產品服務接口
/// </summary>
public interface IProductService
{
List<ProductEntity> GetProductList();
}
3) 服務實現
/// <summary>
/// 獲取列表數據(示例查詢方法,實際會用到分頁,此處用於演示。)
/// </summary>
/// <returns></returns>
public List<ProductEntity> GetProductList()
{
var sql = @"SELECT ID,
ProductName,
ProductCode,
ProductType,
UnitPrice,
CreatedDate
FROM PrdProduct";
var list = QuickReporsitory.Query<ProductEntity>(sql, null)
.ToList();
return list;
}
4) WebApi
/// <summary>
/// 獲取產品列表
/// </summary>
/// <returns></returns>
[HttpGet]
public ResponseResult<List<ProductEntity>> GetProductList()
{
var result = ResponseResult<List<ProductEntity>>.Default();
try
{
var list = ProductService.GetProductList();
result = ResponseResult<List<ProductEntity>>.Success(list);
}
catch (System.Exception ex)
{
result = ResponseResult<List<ProductEntity>>.Error(
string.Format("讀取{0}數據失敗, 錯誤:{1}", "產品列表", ex.Message)
);
}
return result;
}
5) 前端腳本
productlist.load = function () {
jshelper.ajaxGet("/soneweb/api/product/GetProductList", null, function (result) {
if (result.Status == 1) {
var columnProduct = [
{ id: "ID", name: "ID", field: "ID", width: 40, cssClass: "bg-gray" },
{ id: "ProductName", name: "名稱", field: "ProductName", width: 120, cssClass: "bg-gray" },
{ id: "ProductCode", name: "編碼", field: "ProductCode", width: 120, cssClass: "bg-gray" },
{ id: "ProductType", name: "類型", field: "ProductType", width: 160, cssClass: "bg-gray" },
{ id: "UnitPrice", name: "單價", field: "UnitPrice", width: 160, cssClass: "bg-gray" },
{ id: "CreatedDate", name: "創建時間", field: "CreatedDate", width: 200, cssClass: "bg-gray", formatter: datetimeFormatter },
];
var optionsProduct = {
editable: true,
enableCellNavigation: true,
enableColumnReorder: true,
asyncEditorLoading: true,
forceFitColumns: false,
topPanelHeight: 25
};
var dsProduct = result.Entity;
var dvProduct = new Slick.Data.DataView({ inlineFilters: true });
var gridProduct = new Slick.Grid("#myProductGrid", dvProduct, columnProduct, optionsProduct);
dvProduct.onRowsChanged.subscribe(function (e, args) {
gridProduct.invalidateRows(args.rows);
gridProduct.render();
});
dvProduct.onRowCountChanged.subscribe(function (e, args) {
gridProduct.updateRowCount();
gridProduct.render();
});
dvProduct.beginUpdate();
dvProduct.setItems(dsProduct, "ID");
gridProduct.setSelectionModel(new Slick.RowSelectionModel());
dvProduct.endUpdate();
gridProduct.onSelectedRowsChanged.subscribe(function (e, args) {
var selectionRowIndex = args.rows[0];
var row = dvProduct.getItemByIdx(selectionRowIndex);
if (row) {
productlist.mselectedProductID = row.ID;
productlist.mselectedProductRow = row;
}
});
};
});
function datetimeFormatter(row, cell, value, columnDef, dataContext) {
if (value != null && value != "") {
return value.substring(0, 10);
}
}
}
6) 頁面呈現

5. 項目應用場景
SlickOne適用於BS/CS等架構的系統,目前已經用於Web網站項目,電商ERP,OA,工作流和App等各種類型的系統。
6. 項目資源
SlickOne項目開源地址:
http://github.com/besley/slickone
(包含數據庫腳本文件)
SlickOne 做框架基礎的權限管理:
http://github.com/besley/slicksafe
SlickSafe 權限管理在線DEMO:
http://demo.slickflow.com/ssweb/
7. 特別致謝
感謝隨風,青文等網友對項目代碼的貢獻,開源能讓大家集體參與,能讓更多人分享代碼成果。
8. 培訓及技術支持
為團隊開發人員快速上手,Slickflow項目組提供線上開發框架架構設計培訓,流程引擎培訓,SlickGrid插件開發培訓等服務,歡迎留言或咨詢。
9. 在線QQ交流群
QQ群: 151650479
