使用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上,欢迎交流。
新闻热点
疑难解答