Enterprise Library 数据访问应用程序块的关键场景

此文档维护在:http://wiki.entlib.net.cn/EntlibHelp31DataAccessApplicationBlock.ashx

此主题描述了开发人员在访问数据库时必须解决的绝大多数常见情况。每个场景都解释了任务,描述了任务可能出现的真实世界的情况,以及包括示范如何使用数据访问应用程序块完成任务的代码。场景如下:
  • 使用 DbDataReader 获取多行数据。此场景示范了如何能使用 ExecuteReader 方法从数据库中获取多行数据以用表格的形式显示,没有显式的缓存数据,使用 DataSet 对象来操作它,或者将它传递给应用程序中的其他组件。换句话说,它示范了如何尽快的显示结果。
  • 使用 DataSet 来获取多行数据。此场景示范了如何能使用 ExecuteDataSet 方法在组件和多层应用程序层之间传递数据。数据以一个或多个数据表组件,以及可选的将数据链接在一起的关系。
  • 执行一个命令并访问输出参数。此场景示范了如何使用 ExecuteNonQuery 方法来获取包含多个列值的单行数据。
  • 执行一个命令并访问单项结果。此场景示范了如何使用 ExecuteScalar 方法来完成单项查询。
  • 在一个事务中完成多个更新。此场景示范了如何在一个事务中使用 ExecuteNonQuery 中完成对一个数据库的多个操作,它本质上是所有操作要么全部成功,要么全部不成功。
  • 使用 DataSet 更新数据库。此场景示范了如何在修改 DataSet 对象后,可以使用 UpdateDataSet 方法来更新数据库,以使修改持久保存。
  • 获取多行数据为 XML 。此场景示范了如何使用 ExecuteXmlReader 方法从 SQL Server 中获取数据,并得到以 XML 格式返回的数据。

此文档不能帮助你选择用于特殊情况的正确方法(例如,无法帮助你在 DataSetDbDataReader 之间做出选择),而是帮助你使用数据访问应用程序块实现自己的方法。对于数据访问方法的指导,请参见下列的 Microsoft patterns & practices 指南:

4.1 - 使用 DbDataReader 获取多行数据

一种常见的数据库任务是获取并显示信息。例如,一个在线的零售应用程序可能需要显示特定分类中的产品的列表。

典型目标

在此场景中,要从数据库中获取多个数据行并立刻在浏览器显示且仅显示一次,不用显式的缓存数据,不需要用 DataSet 对象操作它,或者将它传递到应用程序中的其他组件。只是简单的尽快使用结果。

目标可以总结如下:
  • 为只读的目的获取数据,这在大多数情况下是要显示数据。
  • 绑定到 Web Form 控件以显示。
  • 不需要要缓存数据。在使用后,数据将被销毁。

解决方案

用存储过程使用 ExecuteReader 方法(由 Database 类提供)。例如,如果应用程序使用在线的分类,就可以传递一个分类的 ID 到存储过程,以指出要获取的产品集。

ExecuteReader 方法返回实现了 IDataReader 接口的对象。Database 类的 ExecuteReader 实现返回一个 DbDataReader 对象。DbDataReader 支持数据绑定,并可以做为许多 ASP.NET 服务器控件的数据源,例如 DataListDataGrid 控件。这提供了有效且灵活的在浏览器输出结果的方法。

快速入门

对于如何使用 ExecuteDataReader 获取多行数据的扩展示例,请参见快速入门漫游,漫游:使用 DbDataReader 获取多行。

使用 ExecuteDataReader

下列代码展示了如何用 SQL 语句使用 ExecuteDataReader 方法。

C#
Database db = DatabaseFactory.CreateDatabase();

using (IDataReader dataReader = db.ExecuteReader(CommandType.Text, "Select Name, Address, City From Customers" ))
{
customerGrid.DataSource = dataReader;
customerGrid.DataBind();
}

Visual Basic
Dim db As Database = DatabaseFactory.CreateDatabase()

Using dataReader As IDataReader = db.ExecuteReader(CommandType.Text, "Select Name, Address, City From Customers")

customerGrid.DataSource = dataReader
customerGrid.DataBind()

End Using

还有其他的可用重载允许开发人员以不同的方式调用 ExecuteReader 方法。可用的重载类型和影响将使用哪个重载的因素的描述,请参见添加应用程序代码。

使用提示

ExecuteReader 方法打开到数据库的连接,并使用 CommandBehavior.CloseConnection 方法来合并连接的生命周期和 reader 。因此,在它完成后,必须马上关闭读取器。关闭读取器将导致连接关闭并返回到连接池中去(假设没有显式的关闭连接池)。使用在示例中的语句确保释放读取器。


4.2 - 使用 DataSet 获取多行数据

在多层系统中,可能需要从数据访问组件传递数据到中间层业务组件。数据从数据库被取出并发送回来,穿过数据访问层,到达业务层。信息被包含在 DataSet 对象中。

典型目标

当在多层系统中访问数据时,通过有下列目标之一:
  • 要获取多个表或者从不同的数据源中获取表。
  • 要与其他应用程序或者组件如 XML Web 服务交换数据。
  • 不得不完成对从数据库中获取的每个记录的昂贵处理。如果使用数据命令和数据读取器,在读取时处理每条记录,会导致连接长时间打开,然后会影响应用程序的性能和可扩展性。
  • 为数据处理访问相互依赖的记录(例如,在相关记录中查找信息)。
  • 要完成 XML 操作,例如在数据上的 XSLT 转换。

解决方案

使用 DataSet 对象达到这些目的是一种很好的途径。ADO.NET DataSet 是一个数据容器,它由一个或多个数据表组成,以及可选的将表链接在一起的关系。它是一个非连接的对象,并且没有任何底层数据源的信息。它支持数据的 XML 操作,而且还是在组件和多层应用程序的层之间传递数据的理想运输工具。

快速入门

对于如何使用 ExecuteDataSet 方法获取多行数据的扩展示例,请参见快速入门漫游,漫游:使用 DataSet 获取多行数据。

使用 ExecuteDataSet

下列代码展示了如何用 DbCommand 对象使用 ExecuteDataSet 方法。

C#
Database db = DatabaseFactory.CreateDatabase();

string sqlCommand = "GetProductsByCategory";
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);

// Retrieve products from category 7.
int category = 7;
db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, category);

DataSet productDataSet = db.ExecuteDataSet(dbCommand);

Visual Basic
Dim db As Database = DatabaseFactory.CreateDatabase()

Dim sqlCommand As String = "GetProductsByCategory"
Dim dbCommand As DbCommand = db.GetStoredProcCommand(sqlCommand)

' Retrieve products from the category 7.
Dim category As Integer = 7
db.AddInParameter(dbCommand, "CategoryID", DbType.Int32, category)

' DataSet that will hold the returned results
Dim customerproductDataSet As DataSet = Nothing

customerproductDataSet = db.ExecuteDataSet(dbCommand)

还有其他的允许开发人员以不同的方式调用 ExecuteReader 方法的可用重载。对于可用的重载类型和影响将使用哪个重载的因素的描述,请参见添加应用程序代码。

使用提示

在使用 ExecuteDataSet 方法的重载时考虑下列提示:
  • 数据访问应用程序块用用于所包含的 DataTable 对象的默认名称生成 DataSet 对象,例如,Table、Table1 和 Table2。
  • 如果要重新使用已存在的 DataSet 而不是新创建一个来保持查询的结果,可以使用 Database 类的 LoadDataSet 方法。


4.3 - 执行一个 Command 并访问输出参数

一个常见的数据库任务是获取特定的多列值。例如,基于 Web 的在线零售应用程序,可能要在用户请求的响应中为特定的商品获取完整的商品信息。

典型目标

在此场景中的典型目标是从特定表中的一行或从不同表的多个相关行中获取特定的数据条目。

解决方案

实现此目标的最有效的方法之一是使用存储过程的输出参数。例如,在一个在线分类中,存储过程接收一个产品 ID 做为输入参数,并通过一个输出参数值返回产品的详细信息。

要调用存储过程,可以使用 ExecuteNonQuery 方法,传递输入和输出参数。在方法返回时,输出参数将由获取的列值所组成。

快速入门

关于如何使用 ExecuteNonQuery 方法获取多行数据的扩展示例,请参见快速入门漫游,漫游:执行一条命令并访问输出参数。

使用 ExecuteNonQuery

下列代码展示了如何用传递 DbCommand 对象来使用 ExecuteNonQuery 方法。

C#
Database db = DatabaseFactory.CreateDatabase();

string sqlCommand = "GetProductDetails";
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);

db.AddInParameter(dbCommand, "ProductID", DbType.Int32, 3);
db.AddOutParameter(dbCommand, "ProductName", DbType.String, 50);
db.AddOutParameter(dbCommand, "UnitPrice", DbType.Currency, 8);

db.ExecuteNonQuery(dbCommand);

string results = string.Format(CultureInfo.CurrentCulture, "{0}, {1}, {2:C} ",
db.GetParameterValue(dbCommand, "ProductID"),
db.GetParameterValue(dbCommand, "ProductName"),
db.GetParameterValue(dbCommand, "UnitPrice"));

Visual Basic
Dim db As Database = DatabaseFactory.CreateDatabase()

Dim sqlCommand As String = "GetProductDetails"
Dim dbCommand As DbCommand = db.GetStoredProcCommand(sqlCommand)

db.AddInParameter(dbCommand, "ProductID", DbType.Int32, 3)
db.AddOutParameter(dbCommand, "ProductName", DbType.String, 50)
db.AddOutParameter(dbCommand, "UnitPrice", DbType.Currency, 8)

db.ExecuteNonQuery(dbCommand)

Dim results As String = String.Format(CultureInfo.CurrentCulture, "{0}, {1}, {2:C} ", _
db.GetParameterValue(dbCommand, "ProductID"), _
db.GetParameterValue(dbCommand, "ProductName"), _
db.GetParameterValue(dbCommand, "UnitPrice"))

还有其他的可用重载允许开发人员以不同的方式调用 ExecuteReader 方法。可用的重载类型和影响将使用哪个重载的因素的描述,请参见添加应用程序代码。

使用提示

在使用 ExecuteNonQuery 方法的重载时可以考虑以下方面:
  • ExecuteNonQuery 方法返回查询所影响的行数(通常是 InsertUpdate、或者 Delete 操作)。
  • 可以使用 ExecuteNonQuery 方法修改数据库中的数据,而不需要通过执行 InsertUpdate 或者 Delete 操作来使用 DataSet


4.4 - 执行一个 Command 并访问单项结果

在许多情况下都要完成单项查询。例如,在线的零售商可能要使用产品 ID 获取产品的名称,或者使用用户 ID 获取信贷级别。

典型目标

在本场景中的目标是返回一个单一值做为查询的结果。

解决方案

返回单一值的有效方法是使用 ExecuteScalar 方法和唯一标识。例如,在一个在线的分类中,可以使用产品的 ID 来获取产品的名称或者可以使用客户的 ID 来获取客户的信贷级别。

快速入门

对于如何使用 ExecuteScalar 获取单项结果的扩展示例,请参见快速入门漫游,漫游:执行一个命令并访问单项结果。

使用 ExecuteScalar

下列代码展示了使用 ExecuteScalar 方法来传递 DbCommand 对象。

C#
Database db = DatabaseFactory.CreateDatabase();

string sqlCommand = "GetProductName";
int productId = 7;
DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand, productId);

string productName = (string)db.ExecuteScalar(dbCommand);

Visual Basic
Dim db As Database = DatabaseFactory.CreateDatabase()

Dim sqlCommand As String = "GetProductName"
Dim productId As Integer = 7
Dim dbCommand As DbCommand = db.GetStoredProcCommand(sqlCommand, productId)

Dim productName As String = DirectCast(db.ExecuteScalar(dbCommand), String)

还有其他的可用重载允许开发人员以不同的方式调用 ExecuteScalar 方法。可用的重载类型和影响将使用哪个重载的因素的描述,请参见添加应用程序代码。

用法提示

在使用 ExecuteScalar 方法的重载时考虑下列几个方面:
  • 获取单项数据的另一种方法是使用存储过程的输出参数或返回值,并结合使用 ExecuteNonQuery 方法。这种方法在不同的困难程度上都行之有效。在这种情况下的代码简单的展示在执行命令并访问输出参数的场景中。关于用于查找单个项目的适当方法的选择的更多信息,请参见 .NET Data Access Architecture Guide

在使用 ExecuteScalar 方法使用结果集返回一个 SQL Server @@Identity 变量时,要知道 SQL Server 返回的 @@Identity 值是 decimal 数据类型,而不是 integer 。如果需要获取的值是整数类型的,就必须在客户应用程序中使用代码进行转换。可以使用 Transact-SQL 的 CAST 函数来返回 integer 类型的值,就如下列示例中的一样。

SELECT CAST(@@Identity AS INTEGER)


4.5 - 在一个事务中完成多个更新

在应用程序执行相对一个数据库的多个操作时,常见的需求时所有的操作必须成功或者数据库必须回滚到初始状态(就是操作前的状态)。这种要么全部要么什么都 不发生的需求被称为事务。事务确保数据库系统的状态的完整性。例如,在一个经典银行业的场景中,应用程序必须从一个帐户中转出,并将特定数量的钱转入另一 个帐户。对于期望的帐户处理,本质上是二个操作要么成功,要么都不成功。这意味着二个操作都在单一的事务环境中完成。

典型目标

在此场景中的典型目标是对一个数据库的所有操作必须成功或者都没完成。

解决方案

有多次方法可以在一个事务中执行数据库方法。在此展示的解决方案示范了如何在一个手工创建的事务环境中使用 ExecuteNonQuery 方法的重载,它通过 ADO.NET 事务支持来构建。

也可以在存储过程中使用 Transact-SQL 语句直接控制手工事务。例如,可以使用单一存储过程来执行事务操作,存储过程使用了 Transact-SQL 语句如 BEGIN TRANSACTIONEND TRANSACTION、和 ROLLBACK TRANSACTION

另 一种方法是使用自动(COM+)事务。自动事务简化了程序模型,因为它们不需要显式的启动新的事务、提交它或者放弃它。而是在运行时,添加声明性属性到 .NET 类上,以指定对象的事务需求。这允许你简单的配置多个组件在同一事务中工作,而且非常适用于必须跨越多个远程数据库的事务。

COM+ 事务特别适用于跨越多个远程数据库的事务。然而,它们也导致了附加的运行时开销,因此在考虑如何很好的要求应用程序执行时必须得小心。

关于事务的更多信息和选择适当的模型的指南,请参见 .NET Data Access Architecture Guide

快速入门

关于如何在一个事务中完成多个更新的扩展示例,请参见快速入门漫游,漫游:在一个事务中完成多个更新。

在一个事务中使用 ExecuteNonQuery

下列代码展示了如何在一个事务中使用多个 ExecuteNonQuery

C#
public bool Transfer(int transactionAmount, int sourceAccount, int destinationAccount)
{
bool result = false;

// Create the database object, using the default database service. The
// default database service is determined through configuration.
Database db = DatabaseFactory.CreateDatabase();

// Two operations, one to credit an account, and one to debit another
// account.
string sqlCommand = "CreditAccount";
DbCommand creditCommand = db.GetStoredProcCommand(sqlCommand);

db.AddInParameter(creditCommand, "AccountID", DbType.Int32, sourceAccount);
db.AddInParameter(creditCommand, "Amount", DbType.Int32, transactionAmount);

sqlCommand = "DebitAccount";
DbCommand debitCommand = db.GetStoredProcCommand(sqlCommand);

db.AddInParameter(debitCommand, "AccountID", DbType.Int32, destinationAccount);
db.AddInParameter(debitCommand, "Amount", DbType.Int32, transactionAmount);

using (DbConnection connection = db.CreateConnection())
{
connection.Open();
DbTransaction transaction = connection.BeginTransaction();

try
{
// Credit the first account.
db.ExecuteNonQuery(creditCommand, transaction);
// Debit the second account.
db.ExecuteNonQuery(debitCommand, transaction);

// Commit the transaction.
transaction.Commit();

result = true;
}
catch
{
// Roll back the transaction.
transaction.Rollback();
}
connection.Close();

return result;
}
}

Visual Basic
Public Function Transfer(ByRef transactionAmount As Integer, ByRef sourceAccount As Integer, ByRef destinationAccount As Integer) As Boolean

Dim result As Boolean = False

' Create the database object, using the default database service. The
' default database service is determined through configuration.
Dim db As Database = DatabaseFactory.CreateDatabase()

' Two operations, one to credit an account, and one to debit another
' account.
Dim sqlCommand As String = "CreditAccount"
Dim creditCommand As DbCommand = db.GetStoredProcCommand(sqlCommand)

db.AddInParameter(creditCommand, "AccountID", DbType.Int32, sourceAccount)
db.AddInParameter(creditCommand, "Amount", DbType.Int32, transactionAmount)

sqlCommand = "DebitAccount"
Dim debitCommand As DbCommand = db.GetStoredProcCommand(sqlCommand)
db.AddInParameter(debitCommand, "AccountID", DbType.Int32, destinationAccount)
db.AddInParameter(debitCommand, "Amount", DbType.Int32, transactionAmount)

Using connection As DbConnection = db.CreateConnection()
connection.Open()
Dim transaction As DbTransaction = connection.BeginTransaction()

Try

' Credit the first account.
db.ExecuteNonQuery(creditCommand, transaction)
' Debit the second account.
db.ExecuteNonQuery(debitCommand, transaction)
' Commit the transaction.
transaction.Commit()

result = True
Catch
' Roll back the transaction.
transaction.Rollback()
End Try

connection.Close()
Return result
End Using
End Function


4.6 - 使用 DataSet 更新数据库

数据库必须定期的用新的信息更新。例如,在基于 Web 的在线零售应用程序中,可能要添加新的客户到数据库中,修改与一个客户 ID 相关的姓名,或者删除完整的客户记录。

典型目标

在此场景中的目标是传输存储在 DataSet 对象中的数据到数据库中。(要记住的是,DataSet 是信息的本地缓存;修改不会自动的传播回原始数据源。)

解决方案

要传播 DataSet 对象中的修改到数据库中,请使用 UpdateDataSet 方法。

快速入门

关于如何使用 DataSet 对象更新数据库的扩展示例,请参见快速入门漫游,漫游:使用 DataSet 更新数据库。

使用 UpdateDataSet

下列代码展示了如何使用 UpdateDataSet 方法。

C#
Database db = DatabaseFactory.CreateDatabase();

DataSet productsDataSet = new DataSet();

string sqlCommand = "Select Select ProductID, ProductName, CategoryID, UnitPrice, LastUpdate From Products";
DbCommand dbCommand = db.GetSqlStringCommand(sqlCommand);

string productsTable = "Products";

// Retrieve the initial data.
db.LoadDataSet(dbCommand, productsDataSet, productsTable);

// Get the table that will be modified.
DataTable table = productsDataSet.Tables[productsTable];

// Add a new product to existing DataSet.
DataRow addedRow = table.Rows.Add(new object[] {DBNull.Value, "New product", 11, 25});

// Modify an existing product.
table.Rows[0]["ProductName"] = "Modified product";

// Establish the Insert, Delete, and Update commands.
DbCommand insertCommand = db.GetStoredProcCommand("AddProduct");
db.AddInParameter(insertCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current);
db.AddInParameter(insertCommand, "CategoryID", DbType.Int32, "CategoryID", DataRowVersion.Current);
db.AddInParameter(insertCommand, "UnitPrice", DbType.Currency, "UnitPrice", DataRowVersion.Current);

DbCommand deleteCommand = db.GetStoredProcCommand("DeleteProduct");
db.AddInParameter(deleteCommand , "ProductID", DbType.Int32, "ProductID", DataRowVersion.Current);

DbCommand updateCommand = db.GetStoredProcCommand("UpdateProduct");
db.AddInParameter(updateCommand, "ProductID", DbType.Int32, "ProductID", DataRowVersion.Current);
db.AddInParameter(updateCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current);
db.AddInParameter(updateCommand, "LastUpdate", DbType.DateTime, "LastUpdate", DataRowVersion.Current);

// Submit the DataSet, capturing the number of rows that were affected.
int rowsAffected = db.UpdateDataSet(productsDataSet, "Products", insertCommand, updateCommand, deleteCommand, Microsoft.Practices.EnterpriseLibrary.Data.UpdateBehavior.Standard);

Visual Basic
Dim db As Database = DatabaseFactory.CreateDatabase()

Dim productsDataSet As DataSet = new DataSet()

Dim sqlCommand As String = "Select Select ProductID, ProductName, CategoryID, UnitPrice, LastUpdate From Products"
Dim dbCommand As DbCommand = db.GetSqlStringCommand(sqlCommand)

Dim productsTable As String = "Products"

' Retrieve the initial data.
db.LoadDataSet(dbCommand, productsDataSet, productsTable)

' Get the table that will be modified.
Dim table As DataTable = productsDataSet.Tables(productsTable)

' Add a new product to existing DataSet.
Dim addedRow As DataRow = table.Rows.Add(New Object() {DBNull.Value, "New product", 11, 25})

' Modify an existing product.
table.Rows(0)("ProductName") = "Modified product"

' Establish the Insert, Delete, and Update commands.
Dim insertCommand As DbCommand = db.GetStoredProcCommand("AddProduct")
db.AddInParameter(insertCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current)
db.AddInParameter(insertCommand, "CategoryID", DbType.Int32, "CategoryID", DataRowVersion.Current)
db.AddInParameter(insertCommand, "UnitPrice", DbType.Currency, "UnitPrice", DataRowVersion.Current)

Dim deleteCommand As DbCommand = db.GetStoredProcCommand("DeleteProduct")
db.AddInParameter(deleteCommand, "@ProductID", DbType.Int32, "ProductID", DataRowVersion.Current)

Dim updateCommand As DbCommand = db.GetStoredProcCommand("UpdateProduct")
db.AddInParameter(updateCommand, "ProductID", DbType.Int32, "ProductID", DataRowVersion.Current)
db.AddInParameter(updateCommand, "ProductName", DbType.String, "ProductName", DataRowVersion.Current)
db.AddInParameter(updateCommand, "LastUpdate", DbType.DateTime, "LastUpdate", DataRowVersion.Current)

' Submit the DataSet, capturing the number of rows that were affected.
Dim rowsAffected As Integer = db.UpdateDataSet(productsDataSet, "Products", insertCommand, updateCommand, _
deleteCommand, Microsoft.Practices.EnterpriseLibrary.Data.UpdateBehavior.Standard)

使用提示

UpdateDataSet 方法可以指定在遇到错误时将发生的行为。此行为必须受 Database 对象的子类支持。前面的示例使用了 UpdateBehavior.Standard ,它指出了如果错误发生时,更新将停在错误点上。没有其他的行受影响,已修改的行也不会发生回滚。其他的更新行为如下:
  • Standard。这不会干涉 DataAdapter 对象的 Update 命令。如果 Update 命令遇到一个错误,更新将停止。Datatable 中的其他行将不会受影响。
  • ContinueDataAdapter 对象的 Update 命令遇到一个错误,更新将继续。Update 命令将尝试更新余下的行。
  • Transactional。如何 DataAdapter 对象遇到一个错误,所有更新的行将回滚。


4.7 - 获取多行 XML 数据

可能要使用 XML 数据的一个例子是,在电子商务应用程序中,它允许客户请求 XML 格式的产品分类。

典型目标

在此场景中,目标是从 SQL Server 数据库中获取 XML 格式的数据。你必须提供一个查询数据库以获取产品分类信息的方法,然后返回给调用者的为 XmlReader

解决方案

SQL Server 2000 以更新的版本提供了 XML 支持并允许从数据库中获取 XML 数据。例如,可能使用 FOR XML 子句从数据库中获取 XML 片段(那就是,没有根元素的 XML 文档)。SqlDatabase 类提供了 ExecuteXmlReader 方法。此方法返回提供仅能前向访问 XML 数据流的 XmlReader 对象,它假定执行的命令包括一条包含有效的 FOR XML 子名的 Transact-SQL 语句。

快速入门

对于如何使用 ExecuteXmlReader 方法获取多行数据为 XML 的扩展示例,请参见快速入门漫游,漫游:获取多行数据为 XML 。

使用 ExecuteXmlReader

下列代码展示了如何使用 ExecuteXmlReader 方法。

C#
SqlDatabase dbSQL = DatabaseFactory.CreateDatabase("EntLibQuickStartsSql") as SqlDatabase;

// Use "FOR XML AUTO" to have SQL return XML data.
string sqlCommand = "SELECT ProductID, ProductName FROM Products FOR XML AUTO";
DbCommand dbCommand = dbSQL.GetSqlStringCommand(sqlCommand);

XmlReader productsReader = null;
StringBuilder productList = new StringBuilder();

try
{
productsReader = dbSQL.ExecuteXmlReader(dbCommand);

// Iterate through the XmlReader and put the data into our results.
while (!productsReader.EOF)
{
if (productsReader.IsStartElement())
{
productList.Append(productsReader.ReadOuterXml());
productList.Append(Environment.NewLine);
}
}
}
finally
{
// Close the Reader.
if (productsReader != null)
{
productsReader.Close();
}
}

Visual Basic
Dim dbSQL As SqlDatabase = DirectCast(DatabaseFactory.CreateDatabase("EntLibQuickStartsSql"), SqlDatabase)

' Use "FOR XML AUTO" to have SQL return XML data.
Dim sqlCommand As String = "SELECT ProductID, ProductName FROM Products FOR XML AUTO"
Dim dbCommand As DbCommand = dbSQL.GetSqlStringCommand(sqlCommand)

Dim productsReader As XmlReader = Nothing
Dim productList As StringBuilder = New StringBuilder()

Try

productsReader = dbSQL.ExecuteXmlReader(dbCommand)

' Iterate through the XmlReader and put the data into our results.
While (Not productsReader.EOF)
If (productsReader.IsStartElement()) Then
productList.Append(productsReader.ReadOuterXml())
productList.Append(Environment.NewLine)
End If
End While

Finally
' Close the Reader if there is no active transaction.
If (Not productsReader Is Nothing And Transaction.Current Is Nothing) Then
productsReader.Close()
End If
End Try

使用提示

在从 XmlReader 中读取数据时,连接必须保持打开。SqlCommand 对象的 ExecuteXmlReader 方法现在不支持 CommandBehavior.CloseConnection 枚举值,所以在完成对读取器的使用且如果不有活动的事务时必须显式的关闭连接。如果 Transaction.Current 静态属性不为 null ,它意味着 TransactionScope 实例是活动的。在这种情况下,不能关闭连接,因为应用程序块为数据库命令使用了共享连接。

另一种选择是,可以调用 ExecuteDataSet 方法之一来获取 DataSet 对象,因为此对象允许将数据视为 XML 来进行操作和访问。然而,使用 SQL Server 的 XML 支持和 FOR XML 子句提供了极大的灵活性,因为它允许决定元素的名称,是否使用严格的元素或属性模式,模式是否将和 XML 数据一起返回,等等。这也意味着避免了与创建 DataSet 或缓存数据相关的性能影响。
posted @ 2007-11-21 23:44  Dorian Deng  阅读(1009)  评论(0编辑  收藏  举报