c# 轻量级ORM框架 实现(一)
c# 輕量級(jí)ORM框架 實(shí)現(xiàn)(一)
2018年09月04日 14:11:02?IT哈?閱讀數(shù):1245發(fā)布一個(gè)自己寫(xiě)的一個(gè)輕量級(jí)ORM框架,本框架設(shè)計(jì)期初基于三層架構(gòu).所以從命名上來(lái)看,了解三層的朋友會(huì)很好理解.
設(shè)計(jì)該框架的目的:不想重復(fù)的寫(xiě)增刪改查,把精力放到功能實(shí)現(xiàn)上.
發(fā)布改框架的原因:希望給初學(xué)者一個(gè)參考,希望能給予好的建議,給自己一個(gè)展示機(jī)會(huì).
在我開(kāi)始之前,先說(shuō)明一下,我對(duì)"軟件工程學(xué)"概念東西幾乎不通,最高文化程度:初二,所以不喜勿噴.
開(kāi)始我的orm設(shè)計(jì)最底層
最底層的是一個(gè)DalBase,它是一個(gè)抽象的,實(shí)現(xiàn)了增刪改查的基本操作.
它既然是一個(gè)抽象的,那么它的內(nèi)部就不應(yīng)該有任何具體成員.
它內(nèi)部核心對(duì)象有:訪問(wèn)數(shù)據(jù)庫(kù)的對(duì)象,生成sql文的對(duì)象的抽象定義,創(chuàng)建sql參數(shù)的抽象方法,where參數(shù)化查詢(xún)對(duì)象的抽象定義.
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /// <summary> /// 訪問(wèn)數(shù)據(jù)的DBHelper對(duì)象 /// </summary> public?abstract?DbHelperBase DBHelper {?get; }?//子類(lèi)實(shí)現(xiàn) /// <summary> /// 獲得生成sql文本的對(duì)象 /// </summary> protected?internal?abstract?BuildSQL BuildSQLTextObj {?get; } /// <summary> /// 獲得數(shù)據(jù)參數(shù)對(duì)象 /// </summary> protected?internal?abstract?DbParameter GetDbParam(string?paramName,?object?paramValue); /// <summary> /// 創(chuàng)建WhereHelper對(duì)象 /// </summary> internal?abstract?WhereHelper CreateWhereHelper(); |
如需擴(kuò)展支持的數(shù)據(jù)庫(kù)種類(lèi),只需要分別對(duì)這幾個(gè)抽象對(duì)象進(jìn)行具體代碼的實(shí)現(xiàn).
以下代碼是增刪改(查詢(xún)相對(duì)來(lái)說(shuō)比較復(fù)雜,單獨(dú)放出來(lái))
?
| 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> ???/// 執(zhí)行sql語(yǔ)句返回所影響行數(shù) ???/// </summary> ???public?virtual?int?ExecuteBySQL(string?sqlText, Dictionary<string,?object> dbParams) ???{ ???????//執(zhí)行sql語(yǔ)句的操作都由此方法實(shí)現(xiàn) ???????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> //這句話其實(shí)內(nèi)部實(shí)現(xiàn)訪問(wèn)了 BuildSQLObj 的 InsertSQLTExtAndParam ,它生成sql語(yǔ)句和sql參數(shù)對(duì)象,把它又寫(xiě)成方法是為了讓子類(lèi)還可以對(duì)它進(jìn)行重寫(xiě),這個(gè)或許之前想多了,直接重寫(xiě)Add也是可以的. ???????GenerateInsertSQLTextAndParam(out?sqlText,?out?dbParams, models); ???????int?rows = ExecuteBySQL(sqlText, dbParams); ???????return?rows; ???} ???/// <summary> ???/// 更新一條或多條記錄,根據(jù)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> ???/// 更新一條或多條記錄,根據(jù)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> ???/// 根據(jù)主鍵刪除記錄 ???/// </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("刪除操作時(shí)主鍵為空!"); ???????} ???????GenerateDeleteSQLTextAndParam<TModel>(out?sqlText,?out?dbParams, pkValues); ???????int?rows = ExecuteBySQL(sqlText, dbParams); ???????return?rows; ???} |
查詢(xún)提供了,3中方法,返回DataSet,返回List,返回DataReader,以及分頁(yè)的方法
?
| 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; } |
為什么有個(gè)DataReader方法呢,返回它有兩個(gè)用處,1是把它轉(zhuǎn)換成List,2因?yàn)镈ataSet的獲取內(nèi)部也是調(diào)用了DataReader方法,(通過(guò)反編譯可以看到的)
因?yàn)镈ataReader 轉(zhuǎn)換 List 要比 DataTable to List的效率要快;
DalBase的的基本功能其實(shí)就差不多了,下邊來(lái)介紹下BLLbase的實(shí)現(xiàn),BLLBase主要實(shí)現(xiàn)了dal方法的一些重載而已,
從字面意思來(lái)說(shuō),業(yè)務(wù)邏輯的基類(lèi),我這里定義了業(yè)務(wù)邏輯的規(guī)則,比如Insert前(后)的事件,查詢(xún)前的事件,等等..
BLLBase里增刪改其實(shí)和DalBase并無(wú)特別差別,就不介紹了.
主要說(shuō)下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); ????????} |
這是一個(gè)帶where條件的查詢(xún),返回datatable,其它獲取List,DataReader,方法都是一樣的,WhereHelper這個(gè)類(lèi)的創(chuàng)建,我自豪了很久,在下面將調(diào)用時(shí)會(huì)舉例它的使用及實(shí)現(xiàn).
舉個(gè)測(cè)試?yán)?
1.創(chuàng)建一個(gè)WinForm程序,引用 ZhCun.Framework.Common 和ZhCunFramework.DataAccess
?
? ?2.創(chuàng)建Models文件夾,分別建Test1.cs和Test2.cs ,這兩個(gè)是表的映射.如下:
?
| 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里面加泛型約束的原因,其實(shí)ModelBase我并沒(méi)有想好用它來(lái)實(shí)現(xiàn)什么,就當(dāng)個(gè)限制條件吧.
另外 ModelAttribute 特性,指定該屬性的映射數(shù)據(jù)庫(kù)表的類(lèi)型及其它規(guī)則,這里Id表示是一個(gè)自增長(zhǎng)的主鍵.
3.創(chuàng)建一個(gè)BLLCommon 類(lèi),這個(gè)類(lèi)名或許叫什么 ?XXXXServer ,或許更好一些,它繼承了BLLBase并指定了連接字符串.
? 那兩個(gè)表就手工建一下吧,連接字符串可以直接指定寫(xiě)死嘍
?
| 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指定了連接字符串和數(shù)據(jù)庫(kù)類(lèi)型,如果一個(gè)項(xiàng)目使用多個(gè)(或多種)數(shù)據(jù)庫(kù),可以創(chuàng)建多個(gè)BLLCommon,
BLLBase的所有方法都定義的虛方法,所以在這里可以重寫(xiě)你要改的東西,來(lái)完成業(yè)務(wù)邏輯的限制或約束.
如,我想要在增加Test1表數(shù)據(jù)時(shí),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); ????????} |
?
下面是調(diào)用代碼:
?此代碼實(shí)現(xiàn)了,新增和更新,及事務(wù)的使用方法.
?
| 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 =?"更新時(shí)間:"?+ 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查詢(xún)的方法調(diào)用:
WhereHelper wh1 = _BllObj.CreateWhereHelper();wh1.Add("Name").Equal("張三");List<Test1> list1 = _BllObj.GetList<Test1>(wh1);WhereHelper對(duì)象為啥要用BLLObj來(lái)創(chuàng)建,這個(gè)解釋一下,考慮到不同數(shù)據(jù)庫(kù)的查詢(xún)應(yīng)該有不同的語(yǔ)法,把WhereHelper抽象出來(lái),也是為了擴(kuò)展.
引用BLLBase的時(shí)候指定了數(shù)據(jù)庫(kù),所以BLL是知道創(chuàng)建哪中數(shù)據(jù)庫(kù)的WhereHelper的,所以用BLL對(duì)象來(lái)創(chuàng)建WhereHelper是最合適的,這樣如果切換數(shù)據(jù)庫(kù)不會(huì)受任何影響.
?
| 1 2 3 4 | wh1.Add("字段1") ???????.Equal(1) ???????.And("字段2") ???????.EqualNot(2);??????? |
這個(gè)是收到j(luò)query的啟發(fā),來(lái)設(shè)計(jì)的類(lèi),每一個(gè)操作都返回了當(dāng)前對(duì)象(即WhereHelper),也就是說(shuō),它可以無(wú)限的"點(diǎn)"下去.
? ? ?使用它的最大好處是:你不用考慮參數(shù)名的重復(fù),不用考慮換庫(kù)的兼容性,操作起來(lái)是如此簡(jiǎn)單.
關(guān)于WHereHelper的使用及設(shè)計(jì)思想請(qǐng)看:??輕量級(jí)ORM框架 之 WhereHelper (二)
?
費(fèi)勁的寫(xiě)了這么多,如果有人看有人有要求,或有什么建議,請(qǐng)留言.
?
昨天看了一篇關(guān)于程序員的文章,一個(gè)優(yōu)秀的程序員6大特質(zhì),其中之一是:懂的分享.
把這套框架源碼共享下 ?下載??
下載說(shuō)明:
本框架沒(méi)有用于過(guò)任何商業(yè)用途(當(dāng)然以后就不一定了)
? ?歡迎 指正,批評(píng),優(yōu)化,建議,抄襲及商業(yè)使用
共享的目的是為了優(yōu)化一下框架,接收一下建議,了解下不足.
?
轉(zhuǎn)自https://www.cnblogs.com/xtdhb/p/3811635.html
轉(zhuǎn)載于:https://www.cnblogs.com/LiZhongZhongY/p/10864159.html
總結(jié)
以上是生活随笔為你收集整理的c# 轻量级ORM框架 实现(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一本通1596动物园
- 下一篇: 汇编语言:实验10 根据材料编程—1.显