c# 轻量级ORM框架 实现(一)

时间:2021-04-10 09:41:33

发布一个自己写的一个轻量级ORM框架,本框架设计期初基于三层架构.所以从命名上来看,了解三层的朋友会很好理解.

设计该框架的目的:不想重复的写增删改查,把精力放到功能实现上.

发布改框架的原因:希望给初学者一个参考,希望能给予好的建议,给自己一个展示机会.

在我开始之前,先说明一下,我对"软件工程学"概念东西几乎不通,最高文化程度:初二,所以不喜勿喷.

开始我的orm设计最底层

最底层的是一个DalBase,它是一个抽象的,实现了增删改查的基本操作.

它既然是一个抽象的,那么它的内部就不应该有任何具体成员.

它内部核心对象有:访问数据库的对象,生成sql文的对象的抽象定义,创建sql参数的抽象方法,where参数化查询对象的抽象定义.

        /// <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();   

如需扩展支持的数据库种类,只需要分别对这几个抽象对象进行具体代码的实现.

以下代码是增删改(查询相对来说比较复杂,单独放出来)

     /// <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;
       //这句话其实内部实现访问了 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, params TModel[] 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,以及分页的方法

public virtual DataTable GetDataTable<TModel>(string sqlWhere, Dictionary<string, object> dbParams, string[] orderFields, bool isDesc, 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, bool isDesc, 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的方法.

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

    c# 轻量级ORM框架 实现(一)

2.创建Models文件夹,分别建Test1.cs和Test2.cs ,这两个是表的映射.如下:

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并指定了连接字符串.

那两个表就手工建一下吧,连接字符串可以直接指定写死喽

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'

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);
}

下面是调用代码:

此代码实现了,新增和更新,及事务的使用方法.

     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是最合适的,这样如果切换数据库不会受任何影响.

        wh1.Add("字段1")
.Equal(1)
.And("字段2")
.EqualNot(2);

  这个是收到jquery的启发,来设计的类,每一个操作都返回了当前对象(即WhereHelper),也就是说,它可以无限的"点"下去.

使用它的最大好处是:你不用考虑参数名的重复,不用考虑换库的兼容性,操作起来是如此简单.

  关于WHereHelper的使用及设计思想请看: 轻量级ORM框架 之 WhereHelper (二)

费劲的写了这么多,如果有人看有人有要求,或有什么建议,请留言.

昨天看了一篇关于程序员的文章,一个优秀的程序员6大特质,其中之一是:懂的分享.

把这套框架源码共享下  下载

下载说明:

  本框架没有用于过任何商业用途(当然以后就不一定了)

    欢迎 指正,批评,优化,建议,抄袭及商业使用

  共享的目的是为了优化一下框架,接收一下建议,了解下不足.

c# 轻量级ORM框架 实现(一)的更多相关文章

  1. 轻量级ORM框架初探-Dapper与PetaPoco的基本使用

    一.EntityFramework EF是传统的ORM框架,也是一个比较重量级的ORM框架.这里仍然使用EF的原因在于为了突出轻量级ORM框架的性能,所谓有对比才有更优的选择. 1.1 准备一张数据库 ...

  2. 轻量级ORM框架 QX&lowbar;Frame&period;Bantina(二、框架使用方式介绍)

    轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...

  3. 轻量级ORM框架 QX&lowbar;Frame&period;Bantina(一、框架简介)

    轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...

  4. &period;NET轻量级ORM框架Dapper入门精通

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

  5. 轻量级ORM框架Dapper应用一:Dapper安装

    一.Dapper简介 Dapper是一款轻量级ORM框架,为解决网站访问流量极高而产生的性能问题而构造,主要通过执行TSQL表达式而实现数据库的CQRS. 如果你在项目中遇到性能访问问题,选择Dapp ...

  6. 分享自己写的基于Dapper的轻量级ORM框架~

    1.说明 本项目是一个使用.NET Standard 2.0开发的,基于 Dapper 的轻量级 ORM 框架,包含基本的CRUD以及根据表达式进行一些操作的方法,目前只针对单表,不包含多表连接操作. ...

  7. C&num; 性能优化 之 秒表 Stopwatch。 Dapper一个和petapoco差不多的轻量级ORM框架

    Sweet小马 小马同学的编程日记. C# 性能优化 之 秒表 Stopwatch. 生词解释:Diagnostics[,daɪəg'nɑstɪks] n.诊断学 using System.Diagn ...

  8. c&num; 轻量级 ORM 框架 之 Model解析 &lpar;四&rpar;

    关于orm框架设计,还有必要说的或许就是Model解析了,也是重要的一个环节,在实现上还是相对比较简单的. Model解析,主要用到的技术是反射了,即:把类的属性与表的字段做映射. 把自己的设计及实现 ...

  9. 轻量级ORM框架 Bankinate

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

随机推荐

  1. 在公有云AZURE上部署私有云AZUREPACK以及WEBSITE CLOUD&lpar;六&rpar;

    (六)在Website Cloud中添加site 1新建Website,并打开 使用前面创建的用户 newbee@waplab.com 登录租户Portal,新建一个website 新建完成后, 可以 ...

  2. Scala学习 —— 元组&amp&semi;映射

    再说集合之前,我们先来回顾一下映射&元祖 映射是键/值对偶的集合,Scala有一个通用的叫法--元组,也就是n个对象的聚集,并不一定要相同类型的.对偶不过是一个n=2的元祖.元祖对于那种需要将 ...

  3. ehcache2&period;8&period;3入门示例:hello world

    一.pom.xml 依赖项 <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehc ...

  4. &OpenCurlyDoubleQuote;PEDIY CrackMe 2007” 下载地址

    工欲善其事,必先利其器.本专辑收集了看雪论坛『CrackMe & ReverseMe』版块2004年4月-2006年12月31期间所有的CrackMe和ReverseMe,共350余个. 下载 ...

  5. Ecshop导航栏标题栏的伪静态设置

    当Ecshop的伪静设置成功之后,左侧的分类标签,包括具体的产品页面都可以顺利的打开伪静态页面,但是点击导航栏,或者标题栏的时候,却还是之前的数据库标签页的方式,这是怎么一回事呢? 这是由于,Ecsh ...

  6. DataGrid 如何得到DataGridRow 和DataGridCell 对象

    第一行为不可编辑  DataGridRow row = (DataGridRow)dataGrid1.ItemContainerGenerator.ContainerFromIndex(0);     ...

  7. poj1741Tree 点分治

    上午学习了点分治,写了1个半小时终于写出一个代码--poj1741,可以说是个模板题. 分治:对于每个儿子找出重心,分别处理 注意:1.每次处理一个重心后,ans减去对它儿子的处理 原因:因为统计方法 ...

  8. Mybatis实体类属性与数据库字段不一致解决办法

    例如:实体类  String userName     数据库:name 解决办法一: 通过给字段加别名,别名写成实体类属性一 eg:select name userName from student ...

  9. 【vue】vue &plus;element 搭建项目,组件之间通信

    父子组件通信 父 通过props属性给 子传递数据 子 操作 父  this.$parent.XXX 子通过$emit传递参数 或者通过vue-bus vue-bus既可以实现父子组件之间的通信,也可 ...

  10. js模块化编程之CommonJS和AMD&sol;CMD

    js模块化编程commonjs.AMD/CMD与ES6模块规范 一.CommonJS commonjs的require是运行时同步加载,es6的import是静态分析,是在编译时而不是在代码运行时.C ...