SqlCommand.BeginExecuteXmlReader 方法
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。
重载
BeginExecuteXmlReader() |
启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。 |
BeginExecuteXmlReader(AsyncCallback, Object) |
通过使用回调过程,启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。 |
BeginExecuteXmlReader()
启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。
public:
IAsyncResult ^ BeginExecuteXmlReader();
public IAsyncResult BeginExecuteXmlReader ();
member this.BeginExecuteXmlReader : unit -> IAsyncResult
Public Function BeginExecuteXmlReader () As IAsyncResult
返回
可用于轮询和/或等待结果的 IAsyncResult;当调用会返回单个 XML 值的 EndExecuteXmlReader
时,也需要该值。
例外
将 Value 设置为 Stream 时,使用的是 SqlDbType 而不是 Binary 或 VarBinary。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
- 或 -
SqlDbType设置为 时ValueTextReader,使用了 Char、NChar、NVarChar、VarChar 或 Xml 以外的其他项。
- 或 -
名称/值对“Asynchronous Processing=true”未包含在为此 SqlCommand 定义连接的连接字符串中。
- 或 -
流式处理操作期间关闭或删除了 SqlConnection。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
流式处理操作期间在 Stream、XmlReader 或 TextReader 对象中出现了错误。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
流式处理操作期间关闭了 Stream、XmlReader 或 TextReader 对象。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
示例
以下控制台应用程序启动异步检索 XML 数据的过程。 在等待结果时,此简单应用程序位于循环中,调查 IsCompleted 属性值。 该过程完成后,代码将检索 XML 并显示其内容。
using System.Data.SqlClient;
using System.Xml;
class Class1
{
static void Main()
{
// This example is not terribly effective, but it proves a point.
// The WAITFOR statement simply adds enough time to prove the
// asynchronous nature of the command.
string commandText =
"WAITFOR DELAY '00:00:03';" +
"SELECT Name, ListPrice FROM Production.Product " +
"WHERE ListPrice < 100 " +
"FOR XML AUTO, XMLDATA";
RunCommandAsynchronously(commandText, GetConnectionString());
Console.WriteLine("Press ENTER to continue.");
Console.ReadLine();
}
private static void RunCommandAsynchronously(
string commandText, string connectionString)
{
// Given command text and connection string, asynchronously execute
// the specified command against the connection. For this example,
// the code displays an indicator as it is working, verifying the
// asynchronous behavior.
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
connection.Open();
IAsyncResult result = command.BeginExecuteXmlReader();
// Although it is not necessary, the following procedure
// displays a counter in the console window, indicating that
// the main thread is not blocked while awaiting the command
// results.
int count = 0;
while (!result.IsCompleted)
{
Console.WriteLine("Waiting ({0})", count++);
// Wait for 1/10 second, so the counter
// does not consume all available resources
// on the main thread.
System.Threading.Thread.Sleep(100);
}
XmlReader reader = command.EndExecuteXmlReader(result);
DisplayProductInfo(reader);
}
}
private static void DisplayProductInfo(XmlReader reader)
{
// Display the data within the reader.
while (reader.Read())
{
// Skip past items that are not from the correct table.
if (reader.LocalName.ToString() == "Production.Product")
{
Console.WriteLine("{0}: {1:C}",
reader["Name"], Convert.ToSingle(reader["ListPrice"]));
}
}
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
// If you have not included "Asynchronous Processing=true" in the
// connection string, the command is not able
// to execute asynchronously.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}
}
Imports System.Data.SqlClient
Imports System.Xml
Module Module1
Sub Main()
' This example is not terribly effective, but it proves a point.
' The WAITFOR statement simply adds enough time to prove the
' asynchronous nature of the command.
Dim commandText As String = _
"WAITFOR DELAY '00:00:03';" & _
"SELECT Name, ListPrice FROM Production.Product " & _
"WHERE ListPrice < 100 " & _
"FOR XML AUTO, XMLDATA"
RunCommandAsynchronously(commandText, GetConnectionString())
Console.WriteLine("Press ENTER to continue.")
Console.ReadLine()
End Sub
Private Sub RunCommandAsynchronously( _
ByVal commandText As String, ByVal connectionString As String)
' Given command text and connection string, asynchronously execute
' the specified command against the connection. For this example,
' the code displays an indicator as it is working, verifying the
' asynchronous behavior.
Using connection As New SqlConnection(connectionString)
Try
Dim command As New SqlCommand(commandText, connection)
connection.Open()
Dim result As IAsyncResult = command.BeginExecuteXmlReader()
' Although it is not necessary, the following procedure
' displays a counter in the console window, indicating that
' the main thread is not blocked while awaiting the command
' results.
Dim count As Integer = 0
While Not result.IsCompleted
count += 1
Console.WriteLine("Waiting ({0})", count)
' Wait for 1/10 second, so the counter
' does not consume all available resources
' on the main thread.
Threading.Thread.Sleep(100)
End While
Using reader As XmlReader = command.EndExecuteXmlReader(result)
DisplayProductInfo(reader)
End Using
Catch ex As SqlException
Console.WriteLine("Error ({0}): {1}", ex.Number, ex.Message)
Catch ex As InvalidOperationException
Console.WriteLine("Error: {0}", ex.Message)
Catch ex As Exception
' You might want to pass these errors
' back out to the caller.
Console.WriteLine("Error: {0}", ex.Message)
End Try
End Using
End Sub
Private Sub DisplayProductInfo(ByVal reader As XmlReader)
' Display the data within the reader.
While reader.Read()
' Skip past items that are not from the correct table.
If reader.LocalName.ToString = "Production.Product" Then
Console.WriteLine("{0}: {1:C}", _
reader("Name"), CSng(reader("ListPrice")))
End If
End While
End Sub
Private Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
' If you have not included "Asynchronous Processing=true" in the
' connection string, the command is not able
' to execute asynchronously.
Return "Data Source=(local);Integrated Security=true;" & _
"Initial Catalog=AdventureWorks; Asynchronous Processing=true"
End Function
End Module
注解
方法 BeginExecuteXmlReader 启动异步执行 Transact-SQL 语句的过程,该语句将行作为 XML 返回,以便其他任务可以在语句执行时并发运行。 语句完成后,开发人员必须调用 EndExecuteXmlReader
方法来完成操作并检索命令返回的 XML。 方法 BeginExecuteXmlReader 会立即返回,但在代码执行相应的 EndExecuteXmlReader
方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。
EndExecuteXmlReader
在命令执行完成之前调用 会导致SqlCommand对象阻塞,直到执行完成。
属性 CommandText 通常指定具有有效 FOR XML 子句的 Transact-SQL 语句。 但是, CommandText
也可以指定返回包含有效 XML 的数据的 ntext
语句。
典型 BeginExecuteXmlReader 查询的格式可以设置为以下 C# 示例中的格式:
SqlCommand command = new SqlCommand("SELECT ContactID, FirstName, LastName FROM dbo.Contact FOR XML AUTO, XMLDATA", SqlConn);
此方法还可用于检索单行、单列结果集。 在这种情况下,如果返回了多行,该方法 EndExecuteXmlReader
会将 XmlReader 附加到第一行的值,并放弃结果集的其余部分。
MARS) 功能 (多个活动结果集允许多个操作使用相同的连接。
请注意,命令文本和参数以同步方式发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,方法会立即返回,而无需等待服务器的答案,即读取是异步的。 虽然命令执行是异步的,但值提取仍然是同步的。
由于此重载不支持回调过程,因此开发人员需要使用 方法返回的 的 IAsyncResult 属性轮询以确定命令是否已完成IsCompleted;或者使用AsyncWaitHandle返回IAsyncResult的 的 属性等待一个或多个命令完成。BeginExecuteXmlReader
如果使用 ExecuteReader 或 BeginExecuteReader 访问 XML 数据,SQL Server将返回长度超过 2,033 个字符的任何 XML 结果,每行 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReader 或 BeginExecuteXmlReader 读取 FOR XML 查询。
此方法忽略 CommandTimeout 属性。
另请参阅
适用于
BeginExecuteXmlReader(AsyncCallback, Object)
通过使用回调过程,启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。
public:
IAsyncResult ^ BeginExecuteXmlReader(AsyncCallback ^ callback, System::Object ^ stateObject);
public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object stateObject);
member this.BeginExecuteXmlReader : AsyncCallback * obj -> IAsyncResult
Public Function BeginExecuteXmlReader (callback As AsyncCallback, stateObject As Object) As IAsyncResult
参数
- callback
- AsyncCallback
命令执行完成时调用的 AsyncCallback 委托。 传递 null
(在 Microsoft Visual Basic 中为 Nothing
)以指示不需要回调。
- stateObject
- Object
传递到回调过程的用户定义的状态对象。 使用 AsyncState 属性从回调过程内检索此对象。
返回
可用于轮询和/或等待结果的 IAsyncResult;当调用 EndExecuteXmlReader(IAsyncResult) 时,也需要该值,用于将命令的结果作为 XML 返回。
例外
将 Value 设置为 Stream 时,使用的是 SqlDbType 而不是 Binary 或 VarBinary。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
- 或 -
SqlDbType设置为 时ValueTextReader,使用了 Char、NChar、NVarChar、VarChar 或 Xml 以外的其他项。
- 或 -
名称/值对“Asynchronous Processing=true”未包含在为此 SqlCommand 定义连接的连接字符串中。
- 或 -
流式处理操作期间关闭或删除了 SqlConnection。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
流式处理操作期间在 Stream、XmlReader 或 TextReader 对象中出现了错误。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
流式处理操作期间关闭了 Stream、XmlReader 或 TextReader 对象。 有关流式处理的详细信息,请参阅 SqlClient 流支持。
示例
以下 Windows 应用程序演示如何使用 BeginExecuteXmlReader 方法,以执行包含几秒钟延迟(模拟长时间运行的命令)的 Transact-SQL 语句。 此示例将正在执行 SqlCommand 的对象作为 stateObject
参数进行传递-这样做使得从回调过程中检索 SqlCommand 对象变得简单,以便代码可以调用 EndExecuteXmlReader 对应于对 的初始调用 BeginExecuteXmlReader的方法。
此示例演示了许多重要的技术。 这包括从单独的线程调用与窗体交互的方法。 此外,此示例演示了如何阻止用户多次同时执行命令,以及如何在调用回调过程之前确保窗体不会关闭。
若要设置此示例,请创建新的 Windows 应用程序。 将 Button 控件、 ListBox 控件和 Label 控件放在窗体上, (接受每个控件的默认名称) 。 将以下代码添加到窗体的 类,根据环境需要修改连接字符串。
using System.Data.SqlClient;
using System.Xml;
namespace Microsoft.AdoDotNet.CodeSamples
{
public partial class Form1 : Form
{
// Hook up the form's Load event handler and then add
// this code to the form's class:
// You need these delegates in order to display text from a thread
// other than the form's thread. See the HandleCallback
// procedure for more information.
private delegate void DisplayInfoDelegate(string Text);
private delegate void DisplayReaderDelegate(XmlReader reader);
private bool isExecuting;
// This example maintains the connection object
// externally, so that it is available for closing.
private SqlConnection connection;
public Form1()
{
InitializeComponent();
}
private string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
// If you do not include the Asynchronous Processing=true name/value pair,
// you wo not be able to execute the command asynchronously.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}
private void DisplayStatus(string Text)
{
this.label1.Text = Text;
}
private void ClearProductInfo()
{
// Clear the list box.
this.listBox1.Items.Clear();
}
private void DisplayProductInfo(XmlReader reader)
{
// Display the data within the reader.
while (reader.Read())
{
// Skip past items that are not from the correct table.
if (reader.LocalName.ToString() == "Production.Product")
{
this.listBox1.Items.Add(String.Format("{0}: {1:C}",
reader["Name"], Convert.ToDecimal(reader["ListPrice"])));
}
}
DisplayStatus("Ready");
}
private void Form1_FormClosing(object sender,
System.Windows.Forms.FormClosingEventArgs e)
{
if (isExecuting)
{
MessageBox.Show(this, "Cannot close the form until " +
"the pending asynchronous command has completed. Please wait...");
e.Cancel = true;
}
}
private void button1_Click(object sender, System.EventArgs e)
{
if (isExecuting)
{
MessageBox.Show(this,
"Already executing. Please wait until the current query " +
"has completed.");
}
else
{
SqlCommand command = null;
try
{
ClearProductInfo();
DisplayStatus("Connecting...");
connection = new SqlConnection(GetConnectionString());
// To emulate a long-running query, wait for
// a few seconds before working with the data.
string commandText =
"WAITFOR DELAY '00:00:03';" +
"SELECT Name, ListPrice FROM Production.Product " +
"WHERE ListPrice < 100 " +
"FOR XML AUTO, XMLDATA";
command = new SqlCommand(commandText, connection);
connection.Open();
DisplayStatus("Executing...");
isExecuting = true;
// Although it is not required that you pass the
// SqlCommand object as the second parameter in the
// BeginExecuteXmlReader call, doing so makes it easier
// to call EndExecuteXmlReader in the callback procedure.
AsyncCallback callback = new AsyncCallback(HandleCallback);
command.BeginExecuteXmlReader(callback, command);
}
catch (Exception ex)
{
isExecuting = false;
DisplayStatus(string.Format("Ready (last error: {0})", ex.Message));
if (connection != null)
{
connection.Close();
}
}
}
}
private void HandleCallback(IAsyncResult result)
{
try
{
// Retrieve the original command object, passed
// to this procedure in the AsyncState property
// of the IAsyncResult parameter.
SqlCommand command = (SqlCommand)result.AsyncState;
XmlReader reader = command.EndExecuteXmlReader(result);
// You may not interact with the form and its contents
// from a different thread, and this callback procedure
// is all but guaranteed to be running from a different thread
// than the form.
// Instead, you must call the procedure from the form's thread.
// One simple way to accomplish this is to call the Invoke
// method of the form, which calls the delegate you supply
// from the form's thread.
DisplayReaderDelegate del = new DisplayReaderDelegate(DisplayProductInfo);
this.Invoke(del, reader);
}
catch (Exception ex)
{
// Because you are now running code in a separate thread,
// if you do not handle the exception here, none of your other
// code catches the exception. Because none of
// your code is on the call stack in this thread, there is nothing
// higher up the stack to catch the exception if you do not
// handle it here. You can either log the exception or
// invoke a delegate (as in the non-error case in this
// example) to display the error on the form. In no case
// can you simply display the error without executing a delegate
// as in the try block here.
// You can create the delegate instance as you
// invoke it, like this:
this.Invoke(new DisplayInfoDelegate(DisplayStatus),
String.Format("Ready(last error: {0}", ex.Message));
}
finally
{
isExecuting = false;
if (connection != null)
{
connection.Close();
}
}
}
private void Form1_Load(object sender, System.EventArgs e)
{
this.button1.Click += new System.EventHandler(this.button1_Click);
this.FormClosing += new System.Windows.Forms.
FormClosingEventHandler(this.Form1_FormClosing);
}
}
}
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
' Add this code to the form's class:
' You need these delegates in order to display text from a thread
' other than the form's thread. See the HandleCallback
' procedure for more information.
Private Delegate Sub DisplayInfoDelegate(ByVal Text As String)
Private Delegate Sub DisplayReaderDelegate(ByVal reader As XmlReader)
Private isExecuting As Boolean
' This example maintains the connection object
' externally, so that it is available for closing.
Private connection As SqlConnection
Private Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
' If you have not included "Asynchronous Processing=true" in the
' connection string, the command is not able
' to execute asynchronously.
Return "Data Source=(local);Integrated Security=true;" & _
"Initial Catalog=AdventureWorks; Asynchronous Processing=true"
End Function
Private Sub DisplayStatus(ByVal Text As String)
Me.Label1.Text = Text
End Sub
Private Sub ClearProductInfo()
' Clear the list box.
Me.ListBox1.Items.Clear()
End Sub
Private Sub DisplayProductInfo(ByVal reader As XmlReader)
' Display the data within the reader.
While reader.Read()
' Skip past items that are not from the correct table.
If reader.LocalName.ToString = "Production.Product" Then
Me.ListBox1.Items.Add(String.Format("{0}: {1:C}", _
reader("Name"), CSng(reader("ListPrice"))))
End If
End While
DisplayStatus("Ready")
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If isExecuting Then
MessageBox.Show(Me, "Cannot close the form until " & _
"the pending asynchronous command has completed. Please wait...")
e.Cancel = True
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
If isExecuting Then
MessageBox.Show(Me, "Already executing. Please wait until the current query " & _
"has completed.")
Else
Dim command As SqlCommand
Try
ClearProductInfo()
DisplayStatus("Connecting...")
connection = New SqlConnection(GetConnectionString())
' To emulate a long-running query, wait for
' a few seconds before working with the data.
Dim commandText As String = _
"WAITFOR DELAY '00:00:03';" & _
"SELECT Name, ListPrice " & _
"FROM Production.Product WHERE ListPrice < 100 " & _
"FOR XML AUTO, XMLDATA"
command = New SqlCommand(commandText, connection)
connection.Open()
DisplayStatus("Executing...")
isExecuting = True
' Although it is not required that you pass the
' SqlCommand object as the second parameter in the
' BeginExecuteXmlReader call, doing so makes it easier
' to call EndExecuteXmlReader in the callback procedure.
Dim callback As New AsyncCallback(AddressOf HandleCallback)
command.BeginExecuteXmlReader(callback, command)
Catch ex As Exception
isExecuting = False
DisplayStatus(String.Format("Ready (last error: {0})", ex.Message))
If connection IsNot Nothing Then
connection.Close()
End If
End Try
End If
End Sub
Private Sub HandleCallback(ByVal result As IAsyncResult)
Try
' Retrieve the original command object, passed
' to this procedure in the AsyncState property
' of the IAsyncResult parameter.
Dim command As SqlCommand = CType(result.AsyncState, SqlCommand)
Dim reader As XmlReader = command.EndExecuteXmlReader(result)
' You may not interact with the form and its contents
' from a different thread, and this callback procedure
' is all but guaranteed to be running from a different thread
' than the form.
' Instead, you must call the procedure from the form's thread.
' One simple way to accomplish this is to call the Invoke
' method of the form, which calls the delegate you supply
' from the form's thread.
Dim del As New DisplayReaderDelegate(AddressOf DisplayProductInfo)
Me.Invoke(del, reader)
Catch ex As Exception
' Because you are now running code in a separate thread,
' if you do not handle the exception here, none of your other
' code catches the exception. Because none of
' your code is on the call stack in this thread, there is nothing
' higher up the stack to catch the exception if you do not
' handle it here. You can either log the exception or
' invoke a delegate (as in the non-error case in this
' example) to display the error on the form. In no case
' can you simply display the error without executing a delegate
' as in the Try block here.
' You can create the delegate instance as you
' invoke it, like this:
Me.Invoke(New DisplayInfoDelegate(AddressOf DisplayStatus), _
String.Format("Ready(last error: {0}", ex.Message))
Finally
isExecuting = False
If connection IsNot Nothing Then
connection.Close()
End If
End Try
End Sub
End Class
注解
方法 BeginExecuteXmlReader 启动异步执行 Transact-SQL 语句或将行作为 XML 返回的存储过程的过程,以便其他任务可以在语句执行时并发运行。 语句完成后,开发人员必须调用 EndExecuteXmlReader 方法来完成操作并检索请求的 XML 数据。 方法 BeginExecuteXmlReader 会立即返回,但在代码执行相应的 EndExecuteXmlReader 方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。 EndExecuteXmlReader在命令执行完成之前调用 会导致SqlCommand对象阻塞,直到执行完成。
属性 CommandText 通常指定具有有效 FOR XML 子句的 Transact-SQL 语句。 但是, CommandText
也可以指定返回包含有效 XML 的数据的语句。 此方法还可用于检索单行、单列结果集。 在这种情况下,如果返回了多行,该方法 EndExecuteXmlReader 会将 XmlReader 附加到第一行的值,并放弃结果集的其余部分。
典型 BeginExecuteXmlReader 查询的格式可以设置为以下 C# 示例中的格式:
SqlCommand command = new SqlCommand("SELECT ContactID, FirstName, LastName FROM Contact FOR XML AUTO, XMLDATA", SqlConn);
此方法还可用于检索单行、单列结果集。 在这种情况下,如果返回了多行,该方法 EndExecuteXmlReader 会将 XmlReader 附加到第一行的值,并放弃结果集的其余部分。
MARS) 功能 (多个活动结果集允许多个操作使用相同的连接。
参数 callback
允许指定在 AsyncCallback 语句完成时调用的委托。 可以从此委托过程内部或应用程序内的任何其他位置调用 EndExecuteXmlReader 方法。 此外,可以传递 参数中的任何 stateObject
对象,并且回调过程可以使用 属性检索此信息 AsyncState 。
请注意,命令文本和参数以同步方式发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,方法会立即返回,而无需等待服务器的答案,即读取是异步的。
在执行操作期间发生的所有错误都会在回调过程中作为异常引发。 必须在回调过程中处理异常,而不是在main应用程序中。 有关在回调过程中处理异常的其他信息,请参阅本主题中的示例。
如果使用 ExecuteReader 或 BeginExecuteReader 访问 XML 数据,SQL Server将返回长度超过 2,033 个字符的任何 XML 结果,每行 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReader 或 BeginExecuteXmlReader 读取 FOR XML 查询。
此方法忽略 CommandTimeout 属性。