c# 輕量級 ORM 框架 之 DBHelper 實現 (三)

  週末了比較悠閒,把本身的orm框架整理了下,開源了.sql

  已經作出來的東西一般感受有些簡單,一些新手或許聽到"框架"一類的詞以爲有些"高深",簡單來講orm就是把ado的封裝.數據庫

在介紹這個框架的第一篇博文,已經把DalBase介紹了一下設計思路,本篇的DBHelper對象也是給dalBase來用的,能夠說框架的全部定義對象都是爲了它.c#

這裏起名叫DBHelper,由於我也是從寫SQLHelper開始的,DBHelper只不過是全部類型對ado操做的各類方法的封裝,因此本篇博文但願給c#新手,或是對ado.net認識比較模糊的有一些幫助.框架

首先DBHelper定義是個抽象的,由於我不知道DalBase 到底要訪問哪一種數據庫,但我知道無論哪中數據庫都會有連接字符串,那我就要求,必需要有鏈接字符串.ide

public DbHelperBase(string connStr)
        {
            _ConnStr = connStr;
        }
View Code

 

DbHelper是個抽象的,那它的成員必然就不能有具體對象.spa

那就把ado.net經常使用的對象定義出來.(若是你是初學者,個人建議是 用到哪一個對象再去定義,不然到後期本身都不知道定義它幹啥呢).net

        protected abstract DbConnection DBConnectionObj { get; }
        protected abstract DbCommand DbCommandObj { get; }
        protected abstract DbDataAdapter DbDataAdapterObj { get; }
        protected DbTransaction DbTransObj;

        public DbConnection CurrentConnection
        {
            get
            {
                return DBConnectionObj;
            }
        }  

說明一下,爲何事務對象不是抽象的,由於事務對象始終是有DbConnection來建立的,我不用知道它具體是什麼類型.設計

DbConnection 對象public也是爲了擴展其它功能而存在的.code

定義了是否事務的變量,全部ado操做都會判斷當前是否處於事務的標記.orm

bool _IsTrans = false;

初學.net的朋友,應該都會有一個SQLHelper的類,我也曾經看過都大同小異,並且廣泛都沒有事務的實現,若是你中槍了,那麼恭喜你,你即將會改變你sqlHelper的實現.

以下代碼:

     /// <summary>
        /// 執行一條指定命令類型(SQL語句或存儲過程等)的SQL語句,返回所影響行數
        /// </summary>
        public int ExecNonQuery(string sqlText, CommandType cmdType, params DbParameter[] param)
        {
            using (SqlConnection conn = new SqlConnection(_ConnStr))
            {
                using (SqlCommand cmd = new SqlCommand(sqlText, conn))
                {
                    cmd.CommandType = cmdType;
                    if (param != null)
                        cmd.Parameters.AddRange(param);
                    conn.Open();
                    return cmd.ExecuteNonQuery();
                }
            }
        }

以上代碼看起來是沒什麼問題,但若是要啓用事務的話想一想是否能夠實現呢?

若是說改造一下加上事務的代碼就行的話

以下:

 SqlTransaction tran = conn.BeginTransaction();
 cmd.Transaction = tran;   

這樣顯然是錯的,由於咱們每每多條執行語句一般是分屢次調用 ExecNonQuery() 方法的.

這樣的一個ado方法的封裝顯然是不合理的.

若是多個增刪改查(注意:查詢也可能在是事務裏)的方法,在一個事務裏,那麼必須是一個數據庫鏈接(Connection)

這就是爲何把那三個對象定義到外面的緣由之一了,最重要的緣由是我須要子類去重寫它.

下面看看個人實現:

        /// <summary>
        /// 打開鏈接,若是已經打開則什麼都不執行了
        /// </summary>
        void OpenConnection()
        {
            if (DBConnectionObj.State != ConnectionState.Open)
            {
                DBConnectionObj.ConnectionString = _ConnStr;
                DBConnectionObj.Open();
            }
        }

/// <summary> /// 給當前DbCommand對象賦值,而且OpenConnection(); /// </summary> void SetCommandAndOpenConnect(string sqlText, CommandType cmdType, params DbParameter[] param) { //按說賦值Connection,CommandType,是不用屢次賦值的 DbCommandObj.CommandType = cmdType; DbCommandObj.Connection = DBConnectionObj; DbCommandObj.Parameters.Clear(); if (param != null) { DbCommandObj.Parameters.AddRange(param); } DbCommandObj.CommandText = sqlText; OpenConnection(); }
        /// <summary>
        /// 執行一條指定命令類型(SQL語句或存儲過程等)的SQL語句,返回所影響行數
        /// </summary>
        public int ExecNonQuery(string sqlText, CommandType cmdType, params DbParameter[] param)
        {
            try
            {
                SetCommandAndOpenConnect(sqlText, cmdType, param);
                return DbCommandObj.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                CloseConnect();
            }
        }

看到這三個方法或許對於初學者會感到迷茫了,沒有看到任何有關事務的代碼呢,兜個圈子,如今想象一下若是加事務的話,須要作什麼?

咱們先從理論上認識一下,事務處理的流程

1.指定事務是哪一個Connection

2.Command的事務對象指定到該事務.

3.Open()

4.提交或回滾(我是能寫漢字的地方毫不寫拼音)

5.關閉鏈接.

繼續說這幾個方法,爲何定義SetCommandAndOpenConnect 和 OpenConnection 這兩個方法,本着儘可能減小重複代碼的原則.僅此而已.

既然Connection和Command都已經定義到方法外了,那就是說我只要再執行Command.ExecuteNonQuery()方法前,給他們賦值就好了.

也就是開始事務只須要給這個兩個對象賦值便可

事務的相關代碼以下:

        /// <summary>
        /// 開始執行事務
        /// </summary>
        public void TransStart()
        {
            OpenConnection();
            DbTransObj = DBConnectionObj.BeginTransaction();
            DbCommandObj.Transaction = DbTransObj;
            _IsTrans = true;
        }
        /// <summary>
        /// 事務提交
        /// </summary>
        public void TransCommit()
        {
            _IsTrans = false;
            DbTransObj.Commit();
            CloseConnect();
        }
        /// <summary>
        /// 事務回滾
        /// </summary>
        public void TransRollback()
        {
            _IsTrans = false;
            DbTransObj.Rollback();
            CloseConnect();
        }

這就是事務的方法了.

最後一個CloseConnect()方法,差點把它遺忘了

        /// <summary>
        /// 關閉鏈接,若是沒有開始事務或鏈接打開時才關閉
        /// </summary>
        void CloseConnect()
        {
            if (!_IsTrans)
            {
                if (DBConnectionObj.State == ConnectionState.Open)
                {
                    DBConnectionObj.Close();
                    DBConnectionObj.Dispose();
                }
            }
        }

當開始事務時,鏈接是不能關的.只有提交了或回滾了纔會把當前鏈接斷掉.

到這裏其實DbHelper的設計基本完成,再貼一下關於查詢的幾個方法,和執行相似就不解釋了.

     /// <summary>
        /// 得到首行首列
        /// </summary>
        public object GetScalar(string sqlText, CommandType cmdType, params DbParameter[] param)
        {
            try
            {
                SetCommandAndOpenConnect(sqlText, cmdType, param);
                return DbCommandObj.ExecuteScalar();

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                CloseConnect();
            }
        }
     /// <summary>
        /// 執行一條SQL語句返回DataSet對象
        /// </summary>
        public DataSet GetDataSet(string sqlText, CommandType cmdType, params DbParameter[] param)
        {
            try
            {
                SetCommandAndOpenConnect(sqlText, cmdType, param);
                DbDataAdapterObj.SelectCommand = DbCommandObj;
                DataSet ds = new DataSet();
                DbDataAdapterObj.Fill(ds);
                return ds;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                CloseConnect();
            }
        }

     /// <summary>
        /// 得到DataReader對象
        /// </summary>
        public DbDataReader GetDataReader(string sqlText, CommandType cmdType, params DbParameter[] param)
        {
            try
            {
                SetCommandAndOpenConnect(sqlText, cmdType, param);
                CommandBehavior cmdBehavior = CommandBehavior.CloseConnection;
                if (_IsTrans)
                {
                    cmdBehavior = CommandBehavior.Default;
                }
                DbDataReader dbReader = DbCommandObj.ExecuteReader(cmdBehavior);
                return dbReader;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                //DataReader用dbReader對象來關閉
                //CloseConnect();
            }
        }

這裏須要注意的是關於返回DataReader對象時不能關閉Connect,和 cmdBehavior 的賦值.

 

好了,到這DBHelper的設計和核心代碼已經所有實現了.

試想一下我如今要完成SQLServerHelper的實現須要作的是什麼?

固然只要實現父類的那幾個抽象屬性就好了.

代碼以下:

 public class SQLHelper : DbHelperBase
    {
        public SQLHelper(string connStr)
            : base(connStr)
        { }

        SqlConnection _DBConnectionObj;
        SqlCommand _DbCommandObj;
        SqlDataAdapter _DbDataAdapterObj;

        protected override DbConnection DBConnectionObj
        {
            get
            {
                //SqlBulkCopy aa = new SqlBulkCopy(new SqlConnection());
                if (_DBConnectionObj == null)
                {
                    _DBConnectionObj = new SqlConnection(_ConnStr);
                }
                return _DBConnectionObj;
            }
        }

        protected override DbCommand DbCommandObj
        {
            get
            {
                if (_DbCommandObj == null)
                {
                    _DbCommandObj = new SqlCommand();
                }
                return _DbCommandObj;
            }
        }

        protected override DbDataAdapter DbDataAdapterObj
        {
            get
            {
                if (_DbDataAdapterObj == null)
                {
                    _DbDataAdapterObj = new SqlDataAdapter();
                }
                return _DbDataAdapterObj;
            }
        }

    }
View Code

OracleHelper,oledbhelper,SQLiteHelper,就不貼代碼了.

 

轉載建議標明出處(我歷來不強迫別人作我管不了的事).

整個框架的源碼在介紹框架的第一篇博文裏有.

歡迎吐槽,點贊,建議,批評,指正,抄襲.

相關文章
相關標籤/搜索