C#通用數據庫操作類


ADO.NET操作

使用ADO.NET的方式操作數據庫時,對於經常需要操作不同數據庫的同學,需要對不同的數據庫翻來覆去地寫操作類。


對ADO.NET,操作數據庫需要有幾個核心的東西(以MySql為例):

MySqlConnection

負責mysql的連接,在操作mysql前,需要先獲得連接。

MySqlCommand

負責具體命令的類,具體需要執行的sql的語句需要放到它的CommandText下。

MySqlDataAdapter

對於查詢數據,可以選擇使用DataAdapter將數據一次性取出到DataSet或者DataTable中。

MySqlDataReader

對於查詢數據,同樣可以使用Reader類對數據進行讀取,與Adapter不同,Reader一次取得一條數據,可以在數據獲取的過程中執行代碼,而不需要等待數據一次性取出。

對於mysql有以上的幾個主要類,對於SQLite、SQL Server,同樣類似。
可以使用一個類來將他們包裝,然后編譯成dll,這樣如果需要操作不同的數據庫,只需要通過工廠創建不同的類即可。

提取相同點

使用ADO.NET方式的數據庫驅動,他們都滿足這么幾個特點:

  • 上面列出的核心類都提供,而且都從對應的基類繼承,例如MySqlConnection從SqlConnection繼承。
  • Command類可以通過對應Connection的CreateCommand方法生成。

那么問題就簡單了,我們只要操作他們的基類就可以了。然后他們的引用通過nuget獲得,這樣就能正常編譯。

//主要代碼

    /// <summary>
    /// 可以根據支持的Sql類型增加或刪除類型,需要增加或刪除對應的GetConnection和GetDbDataAdapter方法。
    /// </summary>
    public enum SqlType
    {
        SqlServer,
        MySql,
        PostgresQL,
        Oracle,
        SQLite,
        //對ODBC方式需要格外注意,目標系統必須預先安裝有對應的數據驅動,如果使用DSN,那么還需要使用配置ODBC數據源
        Odbc
    }
    /// <summary>
    /// 使用ADO.NET控制對數據庫的基本訪問方法,對同一個活動對象(不關閉)線程安全。
    /// </summary>
    public class SqlManipulation : IDisposable
    {

        public SqlManipulation(string strDSN, SqlType sqlType)
        {
            _sqlType = sqlType;
            _strDSN = strDSN;
        }

        #region private variables
        private SqlType _sqlType;
        private string _strDSN;
        private DbConnection _conn;
        private bool _disposed;
        #endregion

        private DbConnection GetConnection()
        {
            DbConnection conn;
            switch (_sqlType)
            {
                case SqlType.SqlServer:
                    conn = new SqlConnection(_strDSN);
                    return conn;
                case SqlType.MySql:
                    conn = new MySqlConnection(_strDSN);
                    return conn;
                case SqlType.PostgresQL:
                    conn = new NpgsqlConnection(_strDSN);
                    return conn;
                case SqlType.Oracle:
                    conn = new OracleConnection(_strDSN);
                    return conn;
                case SqlType.SQLite:
                    conn = new SQLiteConnection(_strDSN);
                    return conn;
                case SqlType.Odbc:
                    conn = new OdbcConnection(_strDSN);
                    return conn;
                default:
                    return null;
            }
        }

        private DbDataAdapter GetDbDataAdapter(string sql)
        {
            DbDataAdapter adp;
            switch (_sqlType)
            {
                case SqlType.SqlServer:
                    adp = new SqlDataAdapter(sql, _conn as SqlConnection);
                    return adp;
                case SqlType.MySql:
                    adp = new MySqlDataAdapter(sql, _conn as MySqlConnection);
                    return adp;
                case SqlType.PostgresQL:
                    adp = new NpgsqlDataAdapter(sql, _conn as NpgsqlConnection);
                    return adp;
                case SqlType.Oracle:
                    adp = new OracleDataAdapter(sql, _conn as OracleConnection);
                    return adp;
                case SqlType.SQLite:
                    adp = new SQLiteDataAdapter(sql, _conn as SQLiteConnection);
                    return adp;
                case SqlType.Odbc:
                    adp = new OdbcDataAdapter(sql, _conn as OdbcConnection);
                    return adp;
                default:
                    return null;
            }
        }

        private DbCommand GetCommand(DbConnection conn, string strSQL)
        {
            DbCommand command = conn.CreateCommand();
            command.CommandText = strSQL;
            return command;
        }

        /// <summary>
        /// 初始化連接並打開
        /// </summary>
        /// <returns></returns>
        public bool Init()
        {
            try
            {
                _conn = GetConnection();
                _conn.Open();
                return true;
            }
            catch (Exception e)
            {
                //記錄日志,退出
                MessageBox.Show(e.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        /// <summary>
        /// 執行SELECT查詢語句,並返回DataTable對象。
        /// </summary>
        /// <param name="strSQL">需要執行的sql語句</param>
        /// <returns>DataTable對象</returns>
        public DataTable ExcuteQuery(string strSQL)
        {
            DbDataAdapter adp = GetDbDataAdapter(strSQL);
            DataTable dt = new DataTable();
            try
            {
                adp.Fill(dt);
            }
            catch (Exception e)
            {
                //記錄日志,並返回空
                MessageBox.Show(strSQL + "\n" + e.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }
            return dt;
        }

        /// <summary>
        /// 執行非Select語句,包括UPDATE DELETE INSERT
        /// </summary>
        /// <param name="strSQL">需要執行的sql語句</param>
        /// <returns>受影響的行數</returns>
        public int ExcuteNonQuery(string strSQL)
        {
            //實例化OdbcCommand對象
            DbCommand myCmd = GetCommand(_conn, strSQL);

            try
            {
                //執行方法
                return myCmd.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                //記錄日志,並返回0
                MessageBox.Show(strSQL + "\n" + e.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return 0;
            }
        }

        /// <summary>
        /// 通過事務批量執行非查詢SQL語句
        /// </summary>
        /// <param name="strSQLs">需要批量執行的SQL</param>
        /// <returns>受影響的行數,發生回滾則返回-1</returns>
        public int ExecuteNonQueryTransaction(List<string> strSQLs)
        {
            DbCommand myCmd = GetCommand(_conn, "");
            int sumAffected = 0;

            DbTransaction transaction = _conn.BeginTransaction();
            myCmd.Transaction = transaction;

            try
            {
                foreach (var n in strSQLs)
                {
                    myCmd.CommandText = n;
                    sumAffected += myCmd.ExecuteNonQuery();
                }
                transaction.Commit();
                return sumAffected;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                transaction.Rollback();
                return -1;
            }
        }
    }
  • 由於不同數據庫對數據類型的實現不同,不同數據庫在操作command parameter上也有一些不同,所以暫時沒有加入到此類中去。
  • 最開始,想使用反射來達到目的,可以避免switch分支,后來想起反射需要知道Assembly名稱,寫這段代碼還不如直接switch。

完整項目代碼github地址:https://github.com/circler3/DatabaseInvoke.git
(現在已經對mysql、sql server、posgresql、sqlite和ODBC方式支持)

未來的改進

  1. 考慮添加EF的支持(引用使用EF的程序,主程序app.config或者web.config需要添加配置項目)
  2. 代碼重構
  3. 數據庫現在是持續保持打開,擬增加其他選項

寫在最后

程序比較簡單,代碼放在github上,歡迎交流。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM