首页 > 学院 > 开发设计 > 正文

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

2019-11-17 03:04:58
字体:
来源:转载
供稿:网友

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

发布一个自己写的一个轻量级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

  

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 =
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表