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<stringobject> 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<stringobject> 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<stringobject> 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<stringobject> 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<stringobject> 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<stringobject> 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<stringobject> 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<stringobject> 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<stringobject> 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 { setget; }

        public string Name { setget; }

        public string Age { setget; }

        public string Remark { setget; }

    }

}

映射的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框架 实现(一)相关推荐

  1. .NET轻量级ORM框架Dapper入门精通

    一.课程介绍 本次分享课程包含两个部分<.NET轻量级ORM框架Dapper修炼手册>和<.NET轻量级ORM框架Dapper葵花宝典>,阿笨将带领大家一起领略轻量级ORM框架 ...

  2. 重磅开源:基于.NET 6.0 自研轻量级ORM框架

    Fast Framework 项目:https://gitee.com/China-Mr-zhong/Fast.Framework 一.前言 1.为了实现快速开发,省去编写大量Sql时间,更好的面向对 ...

  3. 轻量级ORM框架 Bankinate

    [前言] 前面讲过ORM的前世今生,对ORM框架不了解的朋友可以参考博文:https://www.cnblogs.com/7tiny/p/9551754.html 今天,我们主要通过设计一款轻量级的O ...

  4. Python轻量级ORM框架——peewee

    这里写目录标题 Python中常用的ORM框架 peewee使用经验 从数据库中导出模型 查询 统计类查询 优化子查询 参考文章 Python中常用的ORM框架 SQLALchemy:重量级框架,适合 ...

  5. c#自己封装一个轻量级ORM框架FastORM

    在日常进行数据库操作的过程中,我的数据层使用的是微软企业库,但对于多字段的数据的插入与更新时写sql语句就会显得特别费时间,还会经常出现错误耗费时间排查,所以决定基于微软企业库封装一个轻量级的ORM框 ...

  6. Python的轻量级ORM框架peewee

    作者:小小明 在前面的<改变python对象的黑魔法metaclass>一文中,我介绍了使用metaclass自己编写ORM框架的思路. 地址:https://blog.csdn.net/ ...

  7. dapperpoco mysql_Dapper一个和petapoco差不多的轻量级ORM框架

    我们都知道ORM全称叫做Object Relationship Mapper,也就是可以用object来map我们的db,而且市面上的orm框架有很多,其中有一个框架 叫做dapper,而且被称为th ...

  8. 轻量级ORM框架 【Dapper】 的使用

    ORM是什么? 从字面理解,O是Object,对象:R是Relation,关系:M是Mapping,映射.所以,用一句话概括就是:ORM是一种对象关系映射的技术. Dapper 是.NET下的一种OR ...

  9. 轻量级orm框架——gzero指南

    Python微信订餐小程序课程视频 https://edu.csdn.net/course/detail/36074 Python实战量化交易理财系统 https://edu.csdn.net/cou ...

最新文章

  1. 增值税发票OCR识别
  2. 网络推广离不开关键词的精准挖掘
  3. Python编程专属骚技巧4
  4. 【广义找零钱问题】 贪心算法求解进制转换问题
  5. mysql中下杠怎么打_怎么打字母下方的短横杠?,下横杠怎么打
  6. 10种开发以及改善应用的低成本方法
  7. js已知文件路径得到file对象_NodeJs 的几种文件路径
  8. WebService可以远程调试调用
  9. 学习 ASP.NET MVC (第五回)理论篇
  10. 走遍中国《中国古镇全集》
  11. 编写一个简单的widget
  12. scrapy 爬取百度知道,多spider子一个项目中,使用一个pielines
  13. 【Amaple教程】4. 组件
  14. ios 苹果手机适配代码
  15. linux jdk下载并安装
  16. 基于nodejs的excel表格合并工具
  17. html meta标签使用总结
  18. 依靠大数据魔力 阿拉丁金服整合数据优势服务于实体经济
  19. 美国公布全球“野鸡大学”名单
  20. Encyclopaedia Britannica Ultimate 2014电子版下载|大不列颠百科全书

热门文章

  1. python常用的装饰器有哪些_python基本装饰器
  2. flash源文件_Animate/FLASH如何将多个源文件合并
  3. java object转泛型_JAVA快速入门——基本结构、基本数据类型
  4. C++工作笔记-对友元函数的进一步理解
  5. C++工作笔记-在项目中解决编码问题小技巧
  6. QML工作笔记-使用QML中的Date将时间戳和指定格式时间互转
  7. 设计模式工作笔记-UML和设计模式导论
  8. c语言去空格换行符,关于文件操作,碰到空格就换行
  9. 中标麒麟安装rpm包命令_在 Fedora 中安装替代版本的 RPM 包
  10. java编写一个程序_计算已知长和宽的长方形的周长,请教一下大佬们,我们java留了一个作业,编写程序,定义一个接口Comput,声明计算周长和面积的方法...