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

把這套框架源碼共享下  下載  

下載說明:

  本框架沒有用於過任何商業用途(固然之後就不必定了)

    歡迎 指正,批評,優化,建議,抄襲及商業使用

  共享的目的是爲了優化一下框架,接收一下建議,瞭解下不足.

相關文章
相關標籤/搜索