你的位置:首页 > ASP.net教程

[ASP.net教程]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上,欢迎交流。