65.9K
CodeProject 正在变化。 阅读更多。
Home

数据库独立访问

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.59/5 (18投票s)

2005年1月5日

3分钟阅读

viewsIcon

81180

downloadIcon

1081

使用不同的数据库提供程序,而无需将实现绑定到其中一个。

引言

如果您需要将一个使用一个数据库的项目移植到另一个数据库,您就会知道这有多痛苦。通过将所有实现细节隐藏在 DataProvider 中,我们可以通过指定要使用的数据库类型来实现实现独立性。

特点

DataProvider 目前支持 Ole DB 和 SQL Server 提供程序,但您可以轻松地对其进行自定义以支持您希望的提供程序。您可以使用 SQL 参数对数据库执行 SQL 语句,以防止 SQL 注入。 DataProvider 在设计时考虑了连接池,尽管我尚未在生产环境中对其进行测试。使用反射,不再需要编写繁琐的代码来填充类对象。最后,DataProvider 支持非查询 SQL 的数据库事务。

入门

DataProvider.cs 复制到您的项目中,并在必要时为您的项目目的重命名命名空间。 使用 DataProvider 很简单,像这样声明它

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);

如果要使用 SQL 提供程序,请将 OleDb 更改为 SqlServer。 将 ConnectionString 更改为您正在使用的数据库。 现在假设我们要返回整个 Test 表中的行数

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);
DataSet = dp.ExecuteScalar("SELECT COUNT(*) FROM Test;");

很简单,对吧? 这样会更好。 使用参数化 SQL 对于防止 SQL 注入非常重要。 此外,构建字符串会产生难看的代码。 这是另一个更新数据库的片段

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);

DataProvider.Command cmd = 
    dp.CreateCommand("UPDATE Test SET TestString=@TestString;");
cmd.AddParameter("@TestString", "Test123");

dp.ExecuteNonQuery(cmd);

我避免允许 AddParameter() 指定数据类型。 虽然这可能很有用,但它使得迎合不同提供程序支持的不同数据类型变得异常困难。 所有参数都作为对象添加到命令中。

检索 DataReaders 和 DataSets

那么,如果您需要 DataReaderDataSet 提供的强大功能该怎么办? DataProvider 像上面的代码一样轻松地提供这种支持。

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);
try
{
  using (IDataReader reader = dp.ExecuteReader("SELECT * FROM Test;"))
  {
        while (reader.Read())
        {
          for (int i=0; i<reader.FieldCount; i++)
          {
            Response.Write(reader.GetName(i) + ": " + reader.GetValue(i));
          }
        }
        reader.Close();
  }
} 
catch (Exception exception)
{
          System.Diagnostics.Debug.WriteLine(exception.Message);
}

我在这里使用了 using 关键字来确保销毁 IDataReader 对象,从而确保关闭数据库连接,释放服务器的资源。 IDataReader 对象的使用方式与您一直使用它们的方式相同,因此您应该已经熟悉了这一点。 获取和使用 DataGrid 甚至更容易

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);
DataSet = dp.FillDataSet("SELECT * FROM Test;");

请注意,到目前为止我们使用的所有函数都已重载以接受字符串和 Command 对象,因此您可以轻松地在纯 SQL 字符串或参数化 SQL 之间切换。

使用事务

如果没有使用 DataProvider,使用事务从未如此简单。 只需创建一个命令对象数组,然后将其传递给 ExecuteTransaction()。 同样,您可以选择使用纯 SQL 或参数化 SQL。

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);
DataProvider.Command [] commands = new DataProvider.Command[2];

commands[0] = 
    dp.CreateCommand("INSERT INTO Test (TestNumber, TestString, TestDate) 
            VALUES (73, @TestString, @TestDate);");
commands[0].AddParameter("@TestString", "Testing");
commands[0].AddParameter("@TestDate", DateTime.Now);

commands[1] = dp.CreateCommand("UPDATE Test SET TestNumber=44 WHERE ID=2;");
dp.ExecuteTransaction(commands);

使用反射

如果您还不知道,反射允许我们以编程方式访问和修改对象的类信息。 因此,我们可以使用它从数据库表中填充对象。

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);

TestObject obj = new TestObject();
obj = (TestObjec) dp.ReflectObject("SELECT * FROM Test WHERE TestID=37;", 
                                                          obj.GetType());

在这里,TestObject 是一个用户定义的类。 确保类成员变量名称与数据库中的字段名称匹配。 不匹配的字段将被忽略。 我在这里实例化一个新的 TestObject 是因为我需要它来获取其类型。 但是,这是不必要的,因为 ReflectObject() 无论如何都会返回一个新实例。

我尚未找到一种无需实例化(我认为这是运行时识别所必需的)或指定程序集名称即可确定类型的方法。

您还可以使用 DataProvider 来反映对象的多个实例并将其作为 ICollection 返回。

DataProvider dp = 
    new DataProvider(ConnectionString, DataProvider.DBType.OleDb);
TestObject obj = new TestObject();
List = (ArrayList) dp.ReflectCollection("SELECT * FROM Test;", 
                                                obj.GetType());

最终注释

即使您不需要数据库独立访问,DataProvider 也易于使用。 如果您有任何疑问或建议,请发送电子邮件至 me

© . All rights reserved.