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

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

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

发布改框架的缘由:但愿给初学者一个参考,但愿能给予好的建议,给本身一个展现机会.程序员

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

开始个人orm设计最底层数据库

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

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

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

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

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

如下代码是增删改(查询相对来讲比较复杂,单独放出来)测试

     /// <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 = 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大特质,其中之一是:懂的分享.

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

下载说明:

  本框架没有用于过任何商业用途(固然之后就不必定了)

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

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

相关文章
相关标签/搜索