c# 轻量级ORM框架 实现(一)
c# 輕量級ORM框架 實現(一)
2018年09月04日 14:11:02?IT哈?閱讀數:1245發布一個自己寫的一個輕量級ORM框架,本框架設計期初基于三層架構.所以從命名上來看,了解三層的朋友會很好理解.
設計該框架的目的:不想重復的寫增刪改查,把精力放到功能實現上.
發布改框架的原因:希望給初學者一個參考,希望能給予好的建議,給自己一個展示機會.
在我開始之前,先說明一下,我對"軟件工程學"概念東西幾乎不通,最高文化程度:初二,所以不喜勿噴.
開始我的orm設計最底層
最底層的是一個DalBase,它是一個抽象的,實現了增刪改查的基本操作.
它既然是一個抽象的,那么它的內部就不應該有任何具體成員.
它內部核心對象有:訪問數據庫的對象,生成sql文的對象的抽象定義,創建sql參數的抽象方法,where參數化查詢對象的抽象定義.
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /// <summary> /// 訪問數據的DBHelper對象 /// </summary> public?abstract?DbHelperBase DBHelper {?get; }?//子類實現 /// <summary> /// 獲得生成sql文本的對象 /// </summary> protected?internal?abstract?BuildSQL BuildSQLTextObj {?get; } /// <summary> /// 獲得數據參數對象 /// </summary> protected?internal?abstract?DbParameter GetDbParam(string?paramName,?object?paramValue); /// <summary> /// 創建WhereHelper對象 /// </summary> internal?abstract?WhereHelper CreateWhereHelper(); |
如需擴展支持的數據庫種類,只需要分別對這幾個抽象對象進行具體代碼的實現.
以下代碼是增刪改(查詢相對來說比較復雜,單獨放出來)
?
| 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 | /// <summary> ???/// 執行sql語句返回所影響行數 ???/// </summary> ???public?virtual?int?ExecuteBySQL(string?sqlText, Dictionary<string,?object> dbParams) ???{ ???????//執行sql語句的操作都由此方法實現 ???????DbParameter[] parameters = GetDbParam(dbParams); ???????int?rows = DBHelper.ExecNonQuery(sqlText, parameters); ???????return?rows; ???} ???/// <summary> ???/// 新增1條或多條 ???/// </summary> ???public?virtual?int?Add<TModel>(params?TModel[] models)?where?TModel : ModelBase,?new() ???{ ???????ThrowModelIsNullException(models); ???????string?sqlText; ???????Dictionary<string,?object> dbParams;<br> //這句話其實內部實現訪問了 BuildSQLObj 的 InsertSQLTExtAndParam ,它生成sql語句和sql參數對象,把它又寫成方法是為了讓子類還可以對它進行重寫,這個或許之前想多了,直接重寫Add也是可以的. ???????GenerateInsertSQLTextAndParam(out?sqlText,?out?dbParams, models); ???????int?rows = ExecuteBySQL(sqlText, dbParams); ???????return?rows; ???} ???/// <summary> ???/// 更新一條或多條記錄,根據sql條件,指定更新字段(sqlWhere為空,則按主鍵更新) ???/// </summary> ???public?virtual?int?Update<TModel>(string[] fields,?string?sqlWhere, Dictionary<string,?object> dbParams,?params?TModel[] models)?where?TModel : ModelBase,?new() ???{ ???????ThrowModelIsNullException(models); ???????string?sqlText; ???????GenerateUpdateSQLTextAndParam(out?sqlText,?ref?dbParams, sqlWhere, fields, models); ???????int?rows = ExecuteBySQL(sqlText, dbParams); ???????return?rows; ???} ???/// <summary> ???/// 更新一條或多條記錄,根據sql條件,指定忽略更新的字段 ???/// </summary> ???public?virtual?int?UpdateByIgnoreField<TModel>(string[] ignoreFields,?string?sqlWhere, Dictionary<string,?object> dbParams,?paramsTModel[] models)?where?TModel : ModelBase,?new() ???{ ???????string[] allFields = BuildSQLTextObj.GetAllFields<TModel>(); ???????string[] updateFields = BuildSQLTextObj.RemoveFields(allFields, ignoreFields); ???????return?Update(updateFields, sqlWhere, dbParams, models); ???} ???/// <summary> ???/// 根據主鍵刪除記錄 ???/// </summary> ???public?virtual?int?Delete<TModel>(params?object[] pkValues)?where?TModel : ModelBase,?new() ???{ ???????string?sqlText; ???????Dictionary<string,?object> dbParams; ???????if?(pkValues ==?null?|| pkValues.Length < 0) ???????{ ???????????throw?new?DbDataException("刪除操作時主鍵為空!"); ???????} ???????GenerateDeleteSQLTextAndParam<TModel>(out?sqlText,?out?dbParams, pkValues); ???????int?rows = ExecuteBySQL(sqlText, dbParams); ???????return?rows; ???} |
查詢提供了,3中方法,返回DataSet,返回List,返回DataReader,以及分頁的方法
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public?virtual?DataTable GetDataTable<TModel>(string?sqlWhere, Dictionary<string,?object> dbParams,?string[] orderFields,?boolisDesc,?params?string[] selectFields)?where?TModel : ModelBase,?new() { string?sqlText; GenerateSearchSQLTextAndParam<TModel>(sqlWhere, dbParams, orderFields, isDesc,?out?sqlText, selectFields); return?GetDataTableBySQL(sqlText, dbParams); } ? public?virtual?DbDataReader GetDataReader<TModel>(string?sqlWhere, Dictionary<string,?object> dbParams,?string[] orderFields,?boolisDesc,?params?string[] selectFields)?where?TModel : ModelBase,?new() { string?sqlText; GenerateSearchSQLTextAndParam<TModel>(sqlWhere, dbParams, orderFields, isDesc,?out?sqlText, selectFields); return?GetDataReaderBySQL(sqlText, dbParams); } ? public?virtual?List<TModel> GetList<TModel>(string?sqlWhere, Dictionary<string,?object> dbParams,?string[] orderFields,?bool?isDesc,?params?string[] selectFields)?where?TModel : ModelBase,?new() { DbDataReader dbReader = GetDataReader<TModel>(sqlWhere, dbParams, orderFields, isDesc, selectFields); List<TModel> list = GetListByDataReader<TModel>(dbReader); return?list; } |
為什么有個DataReader方法呢,返回它有兩個用處,1是把它轉換成List,2因為DataSet的獲取內部也是調用了DataReader方法,(通過反編譯可以看到的)
因為DataReader 轉換 List 要比 DataTable to List的效率要快;
DalBase的的基本功能其實就差不多了,下邊來介紹下BLLbase的實現,BLLBase主要實現了dal方法的一些重載而已,
從字面意思來說,業務邏輯的基類,我這里定義了業務邏輯的規則,比如Insert前(后)的事件,查詢前的事件,等等..
BLLBase里增刪改其實和DalBase并無特別差別,就不介紹了.
主要說下Get的方法.
?
| 1 2 3 4 5 6 7 8 | public?virtual?DataTable GetDataTable<TModel>(string[] selectFields,?string[] orderFields,?bool?isDesc, WhereHelper dbWhereModel)?where?TModel : ModelBase,?new() ????????{ ? ????????????StringBuilder sqlWhere =?null; ????????????Dictionary<string,?object> dbParam =?null; ????????????GetSqlWhereParam(ref?sqlWhere,?ref?dbParam, dbWhereModel); ????????????return?GetDataTable<TModel>(sqlWhere.ToString(), dbParam, orderFields, isDesc, selectFields); ????????} |
這是一個帶where條件的查詢,返回datatable,其它獲取List,DataReader,方法都是一樣的,WhereHelper這個類的創建,我自豪了很久,在下面將調用時會舉例它的使用及實現.
舉個測試例子:
1.創建一個WinForm程序,引用 ZhCun.Framework.Common 和ZhCunFramework.DataAccess
?
? ?2.創建Models文件夾,分別建Test1.cs和Test2.cs ,這兩個是表的映射.如下:
?
| 1 2 3 4 5 6 7 8 9 10 11 | namespace?ZhCun.Framework.WinTest.Models { ????public?class?Test1 : ModelBase ????{ ????????[ModelAttribute(IsPrimaryKey =?true, IsIdentity =?true)] ????????public?int?Id {?set;?get; } ????????public?string?Name {?set;?get; } ????????public?string?Age {?set;?get; } ????????public?string?Remark {?set;?get; } ????} } |
?映射的Model必須繼承ModelBase,這就是為什么在DalBase里面加泛型約束的原因,其實ModelBase我并沒有想好用它來實現什么,就當個限制條件吧.
另外 ModelAttribute 特性,指定該屬性的映射數據庫表的類型及其它規則,這里Id表示是一個自增長的主鍵.
3.創建一個BLLCommon 類,這個類名或許叫什么 ?XXXXServer ,或許更好一些,它繼承了BLLBase并指定了連接字符串.
? 那兩個表就手工建一下吧,連接字符串可以直接指定寫死嘍
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public?class?BLLCommon : BLLBase ????{ ????????static?string?ConnStr ????????{ ????????????get ????????????{ ????????????????// "Data Source=192.168.0.55;Initial Catalog=aa;uid=sa;pwd=123"; ????????????????return?Configurations.GetConnectString("Test"); ????????????} ????????} ????????public?BLLCommon() ????????????:?base(DatabaseTypeEnum.SQLServer, ConnStr) ????????{ } } |
?BLLCommon指定了連接字符串和數據庫類型,如果一個項目使用多個(或多種)數據庫,可以創建多個BLLCommon,
BLLBase的所有方法都定義的虛方法,所以在這里可以重寫你要改的東西,來完成業務邏輯的限制或約束.
如,我想要在增加Test1表數據時,Remark賦值'aa'
?
| 1 2 3 4 5 6 7 8 9 10 11 12 | public?override?int?Add<TModel>(params?TModel[] models) ????????{ ????????????foreach?(var?item?in?models) ????????????{ ????????????????Test1 m = item?as?Test1; ????????????????if?(m !=?null) ????????????????{ ????????????????????m.Remark =?"aa"; ????????????????} ????????????} ????????????return?base.Add<TModel>(models); ????????} |
?
下面是調用代碼:
?此代碼實現了,新增和更新,及事務的使用方法.
?
| 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 | BLLCommon _BllObj =?new?BLLCommon(); ???private?void?btnAdd_Click(object?sender, EventArgs e) ???{ ???????Test1 t1 =?new?Test1(); ???????Test2 t2 =?new?Test2(); ???????t1.Name = txtName.Text; ???????t1.Age = txtAge.Text; ???????t1.Remark = txtRemark.Text; ???????t2.Name = txtName.Text; ???????t2.Age = txtAge.Text; ???????t2.Remark = txtRemark.Text; ???????try ???????{ ???????????_BllObj.TransStart(); ???????????_BllObj.Add(t2); ???????????_BllObj.Add(t1); ???????????var?model = _BllObj.GetModel<Test1>(1); ???????????if?(model !=?null) ???????????{ ???????????????model.Remark =?"更新時間:"?+ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); ???????????????_BllObj.Update(new?string[] {?"Remark"?}, model); ???????????} ? ???????????_BllObj.TransCommit(); ???????????MessageBox.Show("提交成功!"); ???????} ???????catch?(Exception ex) ???????{ ???????????_BllObj.TransRollback(); ???????????MessageBox.Show(ex.Message); ???????} ???} |
帶where查詢的方法調用:
WhereHelper wh1 = _BllObj.CreateWhereHelper();wh1.Add("Name").Equal("張三");List<Test1> list1 = _BllObj.GetList<Test1>(wh1);WhereHelper對象為啥要用BLLObj來創建,這個解釋一下,考慮到不同數據庫的查詢應該有不同的語法,把WhereHelper抽象出來,也是為了擴展.
引用BLLBase的時候指定了數據庫,所以BLL是知道創建哪中數據庫的WhereHelper的,所以用BLL對象來創建WhereHelper是最合適的,這樣如果切換數據庫不會受任何影響.
?
| 1 2 3 4 | wh1.Add("字段1") ???????.Equal(1) ???????.And("字段2") ???????.EqualNot(2);??????? |
這個是收到jquery的啟發,來設計的類,每一個操作都返回了當前對象(即WhereHelper),也就是說,它可以無限的"點"下去.
? ? ?使用它的最大好處是:你不用考慮參數名的重復,不用考慮換庫的兼容性,操作起來是如此簡單.
關于WHereHelper的使用及設計思想請看:??輕量級ORM框架 之 WhereHelper (二)
?
費勁的寫了這么多,如果有人看有人有要求,或有什么建議,請留言.
?
昨天看了一篇關于程序員的文章,一個優秀的程序員6大特質,其中之一是:懂的分享.
把這套框架源碼共享下 ?下載??
下載說明:
本框架沒有用于過任何商業用途(當然以后就不一定了)
? ?歡迎 指正,批評,優化,建議,抄襲及商業使用
共享的目的是為了優化一下框架,接收一下建議,了解下不足.
?
轉自https://www.cnblogs.com/xtdhb/p/3811635.html
轉載于:https://www.cnblogs.com/LiZhongZhongY/p/10864159.html
總結
以上是生活随笔為你收集整理的c# 轻量级ORM框架 实现(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一本通1596动物园
- 下一篇: 汇编语言:实验10 根据材料编程—1.显