1. 数据库操作类一览
我的数据库操作类一共有如下几种:
类 |
名称 |
描述 |
SqlDBOperate |
SQL-Server数据库操作类 |
执行SQL-Server的数据库操作。 |
OracleDBOperate |
Oracle数据库操作类 |
执行Oracle的数据库操作。 |
OleDBOperate |
OleDb数据库操作类 |
通过OleDb执行数据库操作。 |
ODBCDBOperate |
ODBC数据库操作类 |
通过ODBC执行数据库的操作。 |
2. 如何使用数据库操作类
SqlDBOperate oper = new SqlDBOperate(“…”);
String sql = “…”;
oper. ExecuteNonQuery(sql);
或
DataTable dt = oper.ExecuteDataTable(sql);
3. 数据库操作类的实现
各种数据库操作类的实现比较简单,SqlDBOperate,OracleDBOperate等类的代码不超过30行(当然更多代码放到了基类中),下面是具体操作类的代码:
SqlDBOperate:
using System;
using System.Data.SqlClient;
using System.Data;
namespace DOTNET.Common.Database
{
internal class SqlDBOperate : DBOperate
{
// 在构造方法中创建数据库连接
public SqlDBOperate(string strConnection)
{
this.conn = new SqlConnection(strConnection);
}
// 创建适配器
protected override DbDataAdapter CreateDataAdapter(string sql)
{
return new SqlDataAdapter(sql, (SqlConnection)conn);
}
}
}
OracleDBOperate:
using System;
using System.Data;
using System.Data.OracleClient;
namespace DOTNET.Common.Database
{
public class OracleDBOperate : DBOperate
{
public OracleDBOperate(string strConnection)
{
// 在构造方法中创建数据库连接
this.conn = new OracleConnection(strConnection);
}
// 创建适配器
protected override DbDataAdapter CreateDataAdapter(string sql)
{
return new OracleDataAdapter(sql, (OracleConnection)conn);
}
}
}
OleDBOperate:
using System;
using System.Data.OleDb;
using System.Data;
namespace DOTNET.Common.Database
{
internal class OleDBOperate : DBOperate
{
// 在构造方法中创建数据库连接
public OleDBOperate(string strConnection)
{
this.conn = new OleDbConnection(strConnection);
}
// 创建适配器
protected override DbDataAdapter CreateDataAdapter(string sql)
{
return new OleDbDataAdapter(sql, (OleDbConnection)conn);
}
}
}
ODBCDBOperate:
using System;
using System.Data.Odbc;
using System.Data;
namespace DOTNET.Common.Database
{
internal class ODBCDBOperate : DBOperate
{
// 在构造方法中创建数据库连接
public ODBCDBOperate(string strConnection)
{
this.conn = new OdbcConnection(strConnection);
}
// 创建适配器
protected override DbDataAdapter CreateDataAdapter(string sql)
{
return new OdbcDataAdapter(sql, (OdbcConnection)conn);
}
}
}
其实,在这些数据库操作类中,所完成的仅仅只有在构造函数中创建数据库连接和提供合适的适配器方法而已,其它更多的方法在基类中提供。这样,当我们需要扩展一种新的数据库操作类型时,非常简单,只需要类似上面的10行代码而已。
那么基类都提供哪些功能呢?首先看基类是什么样子。
4. 数据库操作基类的实现
数据库操作基类有些大,有195行代码,程序行总数为385行,在代码后面我会讲解该类,其实该类不是很麻烦:
DBOperate:
/// <copyright>天志(六子) 1999-2007</copyright>
/// <version>1.0</version>
/// <author>天志</author>
/// <email></email>
/// <log date="2007-04-05">创建</log>
using System;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Data;
using System.Data.Common;
namespace DOTNET.Common.Database
{
/// <summary>
/// 数据库操作抽象类。
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public abstract class DBOperate
{
/// <summary>
/// 数据库连接对象。
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
protected DbConnection conn;
/// <summary>
/// 事务处理对象。
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
private DbTransaction trans;
/// <summary>
/// 指示当前操作是否在事务中。
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
private bool bInTrans = false;
#region 打开关闭数据库连接
/// <summary>
/// 打开数据库连接
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
private void Open()
{
if (conn.State.Equals(ConnectionState.Closed))
{
conn.Open();
}
}
/// <summary>
/// 关闭数据库连接
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public void Close()
{
if (conn.State.Equals(ConnectionState.Open)) { conn.Close(); }
}
#endregion
#region 事务支持
/// <summary>
/// 开始一个事务
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public void BeginTran()
{
if (!this.bInTrans)
{
this.Open();
trans = conn.BeginTransaction();
bInTrans = true;
}
}
/// <summary>
/// 提交一个事务
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public void CommitTran()
{
if (this.bInTrans)
{
trans.Commit();
bInTrans = false;
this.Close();
}
}
/// <summary>
/// 回滚一个事务
/// </summary>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public void RollBackTran()
{
if (this.bInTrans)
{
trans.Rollback();
bInTrans = false;
this.Close();
}
}
#endregion
#region 生成命令对象
/// <summary>
/// 获取一个DbCommand对象
/// </summary>
/// <param name="strSql">sql语句名称</param>
/// <param name="parameters">参数数组</param>
/// <param name="strCommandType">命令类型</param>
/// <returns>OdbcCommand对象</returns>
private DbCommand GetPreCommand(string sql, IDataParameter[] parameters)
{
// 初始化一个command对象
DbCommand cmdSql = conn.CreateCommand();
cmdSql.CommandText = sql;
cmdSql.CommandType = this.GetCommandType(sql);
// 判断是否在事务中
if (this.bInTrans) { cmdSql.Transaction = this.trans; }
if (parameters != null)
{
//指定各个参数的取值
foreach (IDataParameter sqlParm in parameters)
{
cmdSql.Parameters.Add(sqlParm);
}
}
return cmdSql;
}
/// <summary>
/// 取得SQL语句的命令类型。
/// </summary>
/// <param name="sql">SQL语句</param>
/// <returns>命令类型</returns>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
private CommandType GetCommandType(string sql)
{
//记录SQL语句的开始字符
string topText = "";
if (sql.Length > 7)
{
//取出字符串的前位
topText = sql.Substring(0, 7).ToUpper();
// 如果不是存储过程
if (topText.Equals("UPDATE ") || topText.Equals("INSERT ") ||
topText.Equals("DELETE ") || topText.Equals("ALTER T") ||
topText.Equals("ALTER ") || topText.Equals("BACKUP ") ||
topText.Equals("RESTORE") || topText.Equals("SELECT "))
{
return CommandType.Text;
}
}
return CommandType.StoredProcedure;
}
#endregion
#region 执行无返回值SQL语句
/// <summary>
/// 执行添加,修改,删除之类的操作。
/// </summary>
/// <param name="strSql">sql语句名称</param>
/// <param name="parameters">参数数组</param>
/// <returns>受影响的条数</returns>
public int ExecuteNonQuery(string sql, IDataParameter[] parameters)
{
DbCommand cmdSql = this.GetPreCommand(sql, parameters);
try
{
// 打开数据库连接
this.Open();
return cmdSql.ExecuteNonQuery();
}
finally
{
// 如果不在事务中
if (!this.bInTrans)
{
this.Close();
}
cmdSql.Parameters.Clear();
}
}
#endregion
#region 返回单个值
/// <summary>
/// 返回结果集中第一行的第一列。
/// </summary>
/// <param name="sql">sql语句名称</param>
/// <param name="parameters">参数数组</param>
/// <returns>返回对象</returns>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public object ExecuteScalar(string sql, IDataParameter[] parameters)
{
//初始化一个command对象
DbCommand cmdSql = this.GetPreCommand(sql, parameters);
try
{
//判断是否在事务中
if (this.bInTrans)
{
cmdSql.Transaction = this.trans;
}
// 打开数据库连接
this.Open();
return cmdSql.ExecuteScalar();
}
finally
{
//判断是否在事务中
if (!this.bInTrans)
{
this.Close();
}
cmdSql.Parameters.Clear();
}
}
#endregion
/// <summary>
/// 返回DataReader。
/// </summary>
/// <param name="sql">sql语句名称</param>
/// <param name="parameters">参数数组</param>
/// <returns>DataReader对象</returns>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public IDataReader ExecuteReader(string sql, IDataParameter[] parameters)
{
//初始化一个command对象
DbCommand cmdSql = this.GetPreCommand(sql, parameters);
try
{
// 打开数据库连接
this.Open();
//返回DataReader对象
return cmdSql.ExecuteReader(CommandBehavior.CloseConnection);
}
finally
{
cmdSql.Parameters.Clear();
}
}
#region 返回DataTable
/// <summary>
/// 返回DataTable。
/// </summary>
/// <param name="sql">sql语句名称</param>
/// <param name="parameters">参数数组</param>
/// <returns>DataTable对象</returns>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public DataTable ExecuteDataTable(string sql, IDataParameter[] parameters)
{
//初始化一个DataAdapter对象,一个DataTable对象
DataTable dt = new DataTable();
DbDataAdapter da = this.CreateDataAdapter(sql);
//初始化一个command对象
DbCommand cmdSql = this.GetPreCommand(sql, parameters);
try
{
//返回DataTable对象
da.SelectCommand = cmdSql;
// 打开数据库连接
this.Open();
da.Fill(dt);
return dt;
}
finally
{
//判断是否在事务中
if (!this.bInTrans)
{
this.Close();
}
cmdSql.Parameters.Clear();
}
}
#endregion
#region 返回DataSet
/// <summary>
/// 返回DataSet对象。
/// </summary>
/// <param name="sql">sql语句名称</param>
/// <param name="tableName">操作表的名称</param>
/// <returns>DataSet对象</returns>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public DataSet ExecuteDataSet(string sql, string tableName)
{
return this.ExecuteDataSet(sql, null, tableName);
}
/// <summary>
/// 返回DataSet对象。
/// </summary>
/// <param name="sql">sql语句名称</param>
/// <param name="parameters">参数数组</param>
/// <param name="strTableName">操作表的名称</param>
/// <returns>DataSet对象</returns>
/// <author>天志</author>
/// <log date="2007-04-05">创建</log>
public DataSet ExecuteDataSet(string sql, IDataParameter[] parameters, string tableName)
{
//初始化一个DataSet对象,一个DataAdapter对象
DataSet ds = new DataSet();
DbDataAdapter da = this.CreateDataAdapter(sql);
//初始化一个command对象
DbCommand cmdSql = this.GetPreCommand(sql, parameters);
try
{
// 返回DataSet对象
da.SelectCommand = cmdSql;
// 打开数据库连接
this.Open();
da.Fill(ds, tableName);
return ds;
}
finally
{
//判断是否在事务中
if (!this.bInTrans)
{
this.Close();
}
cmdSql.Parameters.Clear();
}
}
#endregion
/// <summary>
/// 创建适配器
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
protected abstract DbDataAdapter CreateDataAdapter(string sql);
}
}
基类做了哪些事情呢?
该类的实现思路是:根据传入的SQL语句及SQL 参数数组,生成Command对象,然后执行Command对象,取得执行结果。
1. 首先是:判断传入的SQL参数是SQL语句还是存储过程。这个由方法GetCommandType实现:
如果以:INSERT ,SELECT ,UPDATE ,DELETE , ALTER ,ALTER T…开头的sql参数,为SQL语句,否则即是存储过程。
2. 然后,根据SQL参数与SQL参数数组生成Command对象。这个由方法GetPreCommand实现:
1) 首先根据SQL参数取得Cpmmand的类型(CommandType.Text/CommandType.StoredProcedure).
2) 然后,循环SQL参数数组,将数组中的值赋值给Command对象。
3. 得到Command对象后,即可执行对Comamand的操作。这些方法有:
1) ExecuteNonQuery:执行添加,修改,删除之类的操作。返回值为影响的记录数。
2) ExecuteScalar:返回结果集中第一行的第一列。
3) ExecuteReader:将数据库中的数据读到DataReader中。
4) ExecuteDataSet:将数据库中的数据填充到DataSet中。
5) ExecuteDataTable:将数据库中的数据填充到DataTable中。
4. 剩下的还有:对事务的支持:
1) 变量trans:类型为DbTransaction,事务对象。
2) 变量bInTrans:bool类型,是否启用事务。
3) BeginTran方法:启动事务。
4) CommitTran:提交事务。
5) RollBackTran:事务回滚。
5. 添加事务后,对其他方法的影响:因为添加了事务,所以其他方法也受到影响:
1) 对GetPreCommand的影响:创建Command对象时,需要考虑是否需要设置Transaction。
2) 对执行Comamand操作的影响:出现异常时,判断是否开启事务,如果未开启事务,则关闭连接(因为我假设的是如果不执行事务,则一次执行一条SQL语句:可以去掉本段处理—本段处理时为了在无事务时,防止用户忘记关闭连接所添加的---我觉得这是段很鸡肋的代码)。
6. 最后,还有常用的方法:打开/关闭数据库连接:
1) conn:DbConnection类型,数据库连接对象。
2) Open:打开数据库连接。
3) Close:关闭数据库连接。
在本类中我们无法确定的是:
1) 数据库连接对象的真正类型:有派生类的构造函数负责创建。
2) 适配器(DbDataAdapter)的真正类型:提供抽象函数CreateDataAdapter有派生类负责实现。(CreateDataAdapter方法在ExecuteDataTable,ExecuteDataSet中被调用)
至此,我的数据库操作类介绍完成,这些类经过好几年,许多次的重构才成为现在这个样子,它可以用,但是还不完善,现在把它发布出来,希望能有感兴趣的同行,对它提出修改意见,共同完善它,也希望抛砖引玉。等有时间我把我的重构过程写出来与