使用ADO.NET的方式操作數據庫時,對于經常需要操作不同數據庫的同學,需要對不同的數據庫翻來覆去地寫操作類。
對ADO.NET,操作數據庫需要有幾個核心的東西(以MySQL為例):
負責mysql的連接,在操作mysql前,需要先獲得連接。
負責具體命令的類,具體需要執行的sql的語句需要放到它的CommandText下。
對于查詢數據,可以選擇使用DataAdapter將數據一次性取出到DataSet或者DataTable中。
對于查詢數據,同樣可以使用Reader類對數據進行讀取,與Adapter不同,Reader一次取得一條數據,可以在數據獲取的過程中執行代碼,而不需要等待數據一次性取出。
對于mysql有以上的幾個主要類,對于SQLite、SQL Server,同樣類似。
可以使用一個類來將他們包裝,然后編譯成dll,這樣如果需要操作不同的數據庫,只需要通過工廠創建不同的類即可。
使用ADO.NET方式的數據庫驅動,他們都滿足這么幾個特點:
那么問題就簡單了,我們只要操作他們的基類就可以了。然后他們的引用通過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方式支持)
程序比較簡單,代碼放在github上,歡迎交流。
新聞熱點
疑難解答