/// <summary>
/// 执行SQL语句并返回数据行
/// </summary>
/// <param name="cmdText">数据库命令字符串</param>
/// <returns>数据读取器接口</returns>
public IDataReader ExecuteReader(string cmdText)
{
IDbConnection con = null;
IDbCommand cmd = null;
try
{
con = this.GetConnection();
cmd = this.GetCommand(cmdText, con);
con.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
}
/// <summary>
/// 执行SQL语句并返回单值对象
/// 即结果集中第一行的第一条数据
/// </summary>
/// <param name="cmdText">数据库命令字符串</param>
/// <returns>单值对象-结果集中第一行的第一条数据</returns>
public object ExecuteScalar(string cmdText)
{
IDbConnection con = null;
IDbCommand cmd = null;
try
{
con = this.GetConnection();
cmd = this.GetCommand(cmdText, con);
con.Open();
return cmd.ExecuteScalar();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
finally
{
if (cmd != null)
cmd.Dispose();
if (con != null)
con.Dispose();
}
}
/// <summary>
/// 填充一个数据集对象并返回之
/// </summary>
/// <param name="cmdText">数据库命令字符串</param>
/// <param name="conString">数据库连接字符串</param>
/// <returns>数据集对象</returns>
public DataSet PopulateDataSet(string cmdText, string conString)
{
IDataAdapter da = null;
DataSet ds = null;
try
{
da = this.GetDataAdapter(cmdText, conString);
ds = new DataSet();
da.Fill(ds);
return ds;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
}
/// <summary>
/// 填充一个数据集对象并返回之
/// </summary>
/// <param name="cmdText">数据库命令字符串</param>
/// <returns>数据集对象</returns>
public DataSet PopulateDataSet(string cmdText)
{
IDbConnection con = null;
IDbCommand cmd = null;
IDataAdapter da = null;
DataSet ds = null;
try
{
con = this.GetConnection();
cmd = this.GetCommand(cmdText, con);
da = this.GetDataAdapter(cmd);
ds = new DataSet();
da.Fill(ds);
return ds;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
finally
{
if (cmd != null)
cmd.Dispose();
if (con != null)
con.Dispose();
}
}
}
}
五、构建测试项目
创建完通用数据库访问层,我们来构建一个测试项目。该项目能通过通用数据库访问层同时访问SQL Server 2000和Access 2000中的Northwind数据库。考虑到实际项目中的需求,在开发阶段我们可能仅仅需要Access数据库作为开发平台,而到了实际应用阶段,后台的数据库则须更改为SQL Server或是其他的诸如Oracle、DB2之类的数据库。那么在这种情况下,通用数据库访问层的作用就十分明显了,我们要做的仅仅是更改项目中的数据库类型以及数据库连接字符串,而其他的商业逻辑则可以原封不动。这样带来的益处和效率也是显而易见的。
本测试项目运用了Northwind数据库,其中SQL Server 2000中的是英文版的,而Access 2000中的则为中文版。同时,本测试项目还用到了应用程序配置文件,该文件是一个XML文件,它存储了数据库连接字符串。这样的好处是一旦数据库连接发生变化,我们仅仅需要更改该文件中的相应属性,而不必去更改源代码并重新编译建立项目。该应用程序配置文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="NorthwindProConString" value="server=localhost;database=Northwind;integrated security=SSPI;"/>
<add key="NorthwindDevConString" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Northwind.mdb"/>
</appSettings>
</configuration>
本测试项目主要运用了Windows Froms中的DataGrid控件,它能良好地显示数据源中的数据,项目的主窗体如图2所示。
图2 测试项目的主窗体界面
考虑到DataGrid控件不能直接将数据读取器对象作为数据源,本测试项目还引入了一个功能函数-GetDataTable,它能将一个数据读取器接口中的数据填充到一个数据表对象中并返回该数据表对象,其实现方法如下所示:
/// <summary>
/// 该函数将一个数据读取器接口中的数据
/// 填充到一个数据表对象中并返回数据表对象
/// </summary>
/// <param name="_reader">数据读取器接口</param>
/// <returns>数据表对象</returns>
private System.Data.DataTable GetDataTable(System.Data.IDataReader _reader)
{
System.Data.DataTable _table = _reader.GetSchemaTable();
System.Data.DataTable _dt = new System.Data.DataTable();
System.Data.DataColumn _dc;
System.Data.DataRow _row;
System.Collections.ArrayList _al = new
System.Collections.ArrayList();
for (int i=0; i<_table.Rows.Count; i++)
{
_dc = new System.Data.DataColumn();
if (!
_dt.Columns.Contains(_table.Rows[i]["ColumnName"].ToString()))
{
_dc.ColumnName =
_table.Rows[i]["ColumnName"].ToString();
_dc.Unique =
Convert.ToBoolean(_table.Rows[i]["IsUnique"]);
_dc.AllowDBNull =
Convert.ToBoolean(_table.Rows[i]["AllowDBNull"]);
_dc.ReadOnly =
Convert.ToBoolean(_table.Rows[i]["IsReadOnly"]);
_al.Add(_dc.ColumnName);
_dt.Columns.Add(_dc);
}
}
while (_reader.Read())
{
_row = _dt.NewRow();
for (int i=0; i<_al.Count; i++)
{
_row[((System.String) _al[i])] = _reader[(System.String) _al[i]];
}
_dt.Rows.Add(_row);
}
return _dt;
}
这样,本测试项目就既能以DataReader的方式又能以DataSet的方式来实现数据的显示了,主界面中的四个按钮的消息响应函数分别如下所示:
private void btnDRSQLServer_Click(object sender, System.EventArgs e)
{
try
{
string sqlConStr =
ConfigurationSettings.AppSettings["NorthwindProConString"];
string sqlStr = "SELECT TOP 5 * FROM Customers";
UniversalDAL uDAL = new UniversalDAL(DBType.SQLServer, sqlConStr);
System.Data.IDataReader dr = uDAL.ExecuteReader(sqlStr);
dataGridSQL.DataSource = this.GetDataTable(dr);
}
catch (Exception) {}
}
private void btnDRAccess_Click(object sender, System.EventArgs e)
{
try
{
string oledbConStr =
ConfigurationSettings.AppSettings["NorthwindDevConString"];
string sqlStr = "SELECT TOP 5 * FROM 客户";
UniversalDAL uDAL = new UniversalDAL(DBType.OleDb,
oledbConStr);
System.Data.IDataReader dr = uDAL.ExecuteReader(sqlStr);
dataGridOleDb.DataSource = this.GetDataTable(dr);
}
catch (Exception) {}
}
private void btnDASQLServer_Click(object sender, System.EventArgs e)
{
try
{
string sqlConStr =
ConfigurationSettings.AppSettings["NorthwindProConString"];
string sqlStr = "SELECT TOP 5 * FROM Customers";
UniversalDAL uDAL = new UniversalDAL(DBType.SQLServer, sqlConStr);
DataSet ds = uDAL.PopulateDataSet(sqlStr);
dataGridSQL.DataSource = ds.Tables[0].DefaultView;
}
catch (Exception) {}
}
private void btnDAAccess_Click(object sender, System.EventArgs e)
{
try
{
string oledbConStr =
ConfigurationSettings.AppSettings["NorthwindDevConString"];
string sqlStr = "SELECT TOP 5 * FROM 客户";
UniversalDAL uDAL = new UniversalDAL(DBType.OleDb);
DataSet ds = uDAL.PopulateDataSet(sqlStr, oledbConStr);
dataGridOleDb.DataSource = ds.Tables[0].DefaultView;
}
catch (Exception) {}
}
最后本测试项目运行的效果如图3、图4所示。
图3 本测试项目在DataReader方式下的运行效果
图4 本测试项目在DataSet方式下的运行效果
六、总结 本文研究了运用ADO.NET中数据提供者对象的接口技术实现通用数据库访问层的方法,并给出了一个具体的测试项目以显示通用数据库访问层给实际项目带来的潜在益处和效率。ADO.NET中数据提供者对象的接口技术是非常有用的,而平常开发人员却很容易将其忽视掉,那样的结果就是实际项目的可扩展性、灵活性和通用性大打折扣。而通过运用这项技术,实际项目的通用性,灵活性和可扩展性都获得了大大的提高,这为项目以后可能的升级或移植作好了前期的准备,从而可以减小项目的相关风险系数。最后,笔者希望本文能对广大读者有不少帮助。
|