SqlCommand.BeginExecuteReader 方法
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
重载
| 名称 | 说明 |
|---|---|
| BeginExecuteReader() |
启动由此描述 SqlCommand的 Transact-SQL 语句或存储过程的异步执行,并从服务器检索一个或多个结果集。 |
| BeginExecuteReader(CommandBehavior) |
使用其中一个SqlCommand值启动 Transact-SQL 语句或存储过程CommandBehavior的异步执行。 |
| BeginExecuteReader(AsyncCallback, Object) |
启动由此描述 SqlCommand 的 Transact-SQL 语句或存储过程的异步执行,并使用回调过程将结果作为 XmlReader 对象返回。 |
| BeginExecuteReader(AsyncCallback, Object, CommandBehavior) |
使用其中一个 < |
BeginExecuteReader()
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
启动由此描述 SqlCommand的 Transact-SQL 语句或存储过程的异步执行,并从服务器检索一个或多个结果集。
public:
IAsyncResult ^ BeginExecuteReader();
public IAsyncResult BeginExecuteReader();
member this.BeginExecuteReader : unit -> IAsyncResult
Public Function BeginExecuteReader () As IAsyncResult
返回
可用于轮询或等待结果或同时轮询结果的实例 IAsyncResult ;调用时 EndExecuteReader(IAsyncResult)也需要此值,该值返回 SqlDataReader 可用于检索返回的行的实例。
例外
-
SqlDbType设置为时使用的其他
Binary项或VarBinary已用Value到 Stream。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。 -
除其他项SqlDbType外,
NVarCharVarCharNChar或Xml设置为TextReader时使用Value。Char -
设置为时ValueXmlReader使用的其他
Xml项SqlDbType。
- 执行命令文本时发生的任何错误。
- 流式处理操作期间发生超时。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
- 在 SqlConnection 流式处理操作期间关闭或删除。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
- EnableOptimizedParameterBinding 设置为 true,并且已向集合添加方向输出或 InputOutput 的参数 Parameters 。
流式处理操作期间发生错误StreamXmlReader或TextReader对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
Stream XmlReader流式处理操作期间关闭或TextReader对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
示例
以下控制台应用程序将启动异步检索数据读取器的过程。 等待结果时,此简单应用程序位于循环中,调查 IsCompleted 属性值。 该过程完成后,代码将检索 SqlDataReader 并显示其内容。
using System;
using Microsoft.Data.SqlClient;
class Class1
{
static void Main()
{
// This is a simple example that demonstrates the usage of the
// BeginExecuteReader functionality
// The WAITFOR statement simply adds enough time to prove the
// asynchronous nature of the command.
string commandText =
"WAITFOR DELAY '00:00:03';" +
"SELECT LastName, FirstName FROM Person.Contact " +
"WHERE LastName LIKE 'M%'";
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))
{
try
{
SqlCommand command = new SqlCommand(commandText, connection);
connection.Open();
IAsyncResult result = command.BeginExecuteReader();
// Although it is not necessary, the following code
// 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)
{
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.
System.Threading.Thread.Sleep(100);
}
using (SqlDataReader reader = command.EndExecuteReader(result))
{
DisplayResults(reader);
}
}
catch (SqlException ex)
{
Console.WriteLine("Error ({0}): {1}", ex.Number, ex.Message);
}
catch (InvalidOperationException ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
catch (Exception ex)
{
// You might want to pass these errors
// back out to the caller.
Console.WriteLine("Error: {0}", ex.Message);
}
}
}
private static void DisplayResults(SqlDataReader reader)
{
// Display the data within the reader.
while (reader.Read())
{
// Display all the columns.
for (int i = 0; i < reader.FieldCount; i++)
{
Console.Write("{0}\t", reader.GetValue(i));
}
Console.WriteLine();
}
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks";
}
}
注解
该方法 BeginExecuteReader() 启动异步执行返回行的 Transact-SQL 语句或存储过程的过程,以便其他任务在执行语句时可以并发运行。 语句完成后,开发人员必须调用 EndExecuteReader(IAsyncResult) 该方法来完成操作并检索 SqlDataReader 命令返回的操作。 该方法 BeginExecuteReader() 会立即返回,但在代码执行相应的 EndExecuteReader(IAsyncResult) 方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。 EndExecuteReader(IAsyncResult)在命令的执行完成之前调用该对象会导致SqlCommand对象阻塞,直到执行完成。
请注意,命令文本和参数将同步发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,该方法会立即返回,而无需等待来自服务器的答案,即读取是异步的。 尽管命令执行是异步的,但提取值仍然同步。 这意味着,如果需要更多数据以及基础网络的读取操作块,则调用 Read() 可能会阻止。
由于此重载不支持回调过程,因此开发人员必须轮询以确定命令是否已完成,使用IsCompleted方法返回IAsyncResult的属性BeginExecuteReader();或使用返回AsyncWaitHandle的属性等待完成一个或多个命令IAsyncResult。
如果使用 ExecuteReader() 或 BeginExecuteReader() 访问 XML 数据,SQL Server 将返回长度大于 2,033 个字符的任何 XML 结果,每行包含 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReader() 或 BeginExecuteXmlReader() 读取 FOR XML 查询。
此方法忽略 CommandTimeout 属性。
适用于
BeginExecuteReader(CommandBehavior)
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
使用其中一个SqlCommand值启动 Transact-SQL 语句或存储过程CommandBehavior的异步执行。
public:
IAsyncResult ^ BeginExecuteReader(System::Data::CommandBehavior behavior);
public IAsyncResult BeginExecuteReader(System.Data.CommandBehavior behavior);
member this.BeginExecuteReader : System.Data.CommandBehavior -> IAsyncResult
Public Function BeginExecuteReader (behavior As CommandBehavior) As IAsyncResult
参数
- behavior
- CommandBehavior
值之 CommandBehavior 一,指示语句执行和数据检索的选项。
返回
可用于轮询、等待结果或同时轮询结果的实例 IAsyncResult ;调用时 EndExecuteReader(IAsyncResult)也需要此值,该值返回 SqlDataReader 可用于检索返回的行的实例。
例外
-
SqlDbType设置为时使用的其他
Binary项或VarBinary已用Value到 Stream。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。 -
除其他项SqlDbType外,
NVarCharVarCharNChar或Xml设置为TextReader时使用Value。Char -
设置为时ValueXmlReader使用的其他
Xml项SqlDbType。
- 执行命令文本时发生的任何错误。
- 流式处理操作期间发生超时。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
- 在 SqlConnection 流式处理操作期间关闭或删除。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
- EnableOptimizedParameterBinding 设置为 true,并且已向集合添加方向输出或 InputOutput 的参数 Parameters 。
流式处理操作期间发生错误StreamXmlReader或TextReader对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
Stream XmlReader流式处理操作期间关闭或TextReader对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
示例
以下控制台应用程序将启动异步检索数据读取器的过程。 等待结果时,此简单应用程序位于循环中,调查 IsCompleted 属性值。 该过程完成后,代码将 SqlDataReader 检索并显示其内容。
此示例还传递 CloseConnection 行为参数中的和 SingleRow 值,导致关闭返回 SqlDataReader 的连接关闭,并针对单个行结果进行优化。
using System;
using System.Data;
using Microsoft.Data.SqlClient;
class Class1
{
static void Main()
{
// This example is not terribly useful, 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 ProductID, Name FROM Production.Product WHERE ListPrice < 100";
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.
try
{
// The code does not need to handle closing the connection explicitly--
// the use of the CommandBehavior.CloseConnection option takes care
// of that for you.
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(commandText, connection);
connection.Open();
IAsyncResult result = command.BeginExecuteReader(CommandBehavior.CloseConnection);
// Although it is not necessary, the following code
// 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);
}
using (SqlDataReader reader = command.EndExecuteReader(result))
{
DisplayResults(reader);
}
}
catch (SqlException ex)
{
Console.WriteLine("Error ({0}): {1}", ex.Number, ex.Message);
}
catch (InvalidOperationException ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
catch (Exception ex)
{
// You might want to pass these errors
// back out to the caller.
Console.WriteLine("Error: {0}", ex.Message);
}
}
private static void DisplayResults(SqlDataReader reader)
{
// Display the data within the reader.
while (reader.Read())
{
// Display all the columns.
for (int i = 0; i < reader.FieldCount; i++)
{
Console.Write("{0}\t", reader.GetValue(i));
}
Console.WriteLine();
}
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks";
}
}
注解
该方法 BeginExecuteReader() 启动异步执行返回行的 Transact-SQL 语句或存储过程的过程,以便其他任务在执行语句时可以并发运行。 语句完成后,开发人员必须调用 EndExecuteReader(IAsyncResult) 该方法来完成操作并检索 SqlDataReader 命令返回的操作。 该方法 BeginExecuteReader() 会立即返回,但在代码执行相应的 EndExecuteReader(IAsyncResult) 方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。 EndExecuteReader(IAsyncResult)在命令的执行完成之前调用该对象会导致SqlCommand对象阻塞,直到执行完成。
通过此参数 behavior ,可以指定控制命令及其连接行为的选项。 这些值可以组合在一起(使用编程语言的 OR 运算符);通常,开发人员使用 CommandBehavior.CloseConnection 该值来确保关闭时 SqlDataReader 运行时关闭连接。
请注意,命令文本和参数将同步发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,该方法会立即返回,而无需等待来自服务器的答案,即读取是异步的。 尽管命令执行是异步的,但提取值仍然同步。 这意味着,如果需要更多数据以及基础网络的读取操作块,则调用 Read() 可能会阻止。
由于此重载不支持回调过程,因此开发人员必须轮询以确定命令是否已完成,使用IsCompleted方法返回IAsyncResult的属性BeginExecuteNonQuery();或使用返回AsyncWaitHandle的属性等待完成一个或多个命令IAsyncResult。
如果使用 ExecuteReader() 或 BeginExecuteReader() 访问 XML 数据,SQL Server 将返回长度超过 2,033 个字符的任何 XML 结果,每行包含 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReader() 或 BeginExecuteXmlReader() 读取 FOR XML 查询。
此方法忽略 CommandTimeout 属性。
适用于
BeginExecuteReader(AsyncCallback, Object)
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
启动由此描述 SqlCommand 的 Transact-SQL 语句或存储过程的异步执行,并使用回调过程将结果作为 XmlReader 对象返回。
public:
IAsyncResult ^ BeginExecuteReader(AsyncCallback ^ callback, System::Object ^ stateObject);
public IAsyncResult BeginExecuteReader(AsyncCallback callback, object stateObject);
member this.BeginExecuteReader : AsyncCallback * obj -> IAsyncResult
Public Function BeginExecuteReader (callback As AsyncCallback, stateObject As Object) As IAsyncResult
参数
- callback
- AsyncCallback
命令 AsyncCallback 执行完成后调用的委托。 通过
null (Microsoft Visual Basic 中的 Nothing) 指示不需要回调。
- stateObject
- Object
传递给回调过程的用户定义状态对象。 使用 AsyncState 属性从回调过程中检索此对象。
返回
IAsyncResult可用于轮询、等待结果或同时轮询结果;调用时EndExecuteXmlReader(IAsyncResult)也需要此值,它将命令的结果返回为 XML。
例外
如果设置为 Stream ,则使用Value二进制或 VarBinary 以外的其他SqlDbType项。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
-or-
设置为
-or-
在 SqlConnection 流式处理操作期间关闭或删除。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
- or -
<xref data-throw-if-not-resolved="true" uid="Microssoft.Data.SqlClient.SqlCommand.EnableOptimizedParameterBinding"></xref>
is set to true and a parameter with direction Output or InputOutput has been added to the <xref data-throw-if-not-resolved="true" uid="Microsoft.Data.SqlClient.SqlCommand.Parameters"></xref> collection.
流式处理操作期间发生错误StreamXmlReader或TextReader对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
XmlReader TextReader流式处理操作期间关闭或Stream对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
示例
以下 Windows 应用程序演示如何使用 BeginExecuteXmlReader 方法,以执行包含几秒钟延迟(模拟长时间运行的命令)的 Transact-SQL 语句。 此示例将执行 SqlCommand 的对象作为 stateObject 参数传递-这样做使从回调过程中检索 SqlCommand 对象变得简单,以便代码可以调用 EndExecuteXmlReader 与初始调用 BeginExecuteXmlReader对应的方法。
此示例演示了许多重要的技术。 这包括从单独的线程调用与表单交互的方法。 此外,此示例演示了如何阻止用户多次并发执行命令,以及如何确保在调用回调过程之前窗体未关闭。
若要设置此示例,请创建新的 Windows 应用程序。 Button将控件、ListBox控件和Label控件放在窗体上(接受每个控件的默认名称)。 将以下代码添加到窗体的类,根据需要修改环境的连接字符串。
/* This does not compile, as multiple methods are missing.
// <Snippet1>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Data.SqlClient;
using System.Xml;
namespace SqlCommand_BeginExecuteXmlReaderAsync
{
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.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks";
}
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);
}
}
}
// </Snippet1>
*/
注解
该方法 BeginExecuteXmlReader 开始异步执行以 XML 形式返回行的 Transact-SQL 语句或存储过程的过程,以便其他任务在执行语句时可以并发运行。 语句完成后,开发人员必须调用 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 。
请注意,命令文本和参数将同步发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,该方法会立即返回,而无需等待来自服务器的答案,即读取是异步的。
在执行操作期间发生的所有错误都会作为回调过程中的异常引发。 必须在回调过程中处理异常,而不是在主应用程序中处理。 有关在回调过程中处理异常的其他信息,请参阅本主题中的示例。
如果使用 ExecuteReader 或 BeginExecuteReader 访问 XML 数据,SQL Server 将返回长度大于 2,033 个字符的任何 XML 结果,每行包含 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReader 或 BeginExecuteXmlReader 读取 FOR XML 查询。
此方法忽略 CommandTimeout 属性。
另请参阅
适用于
BeginExecuteReader(AsyncCallback, Object, CommandBehavior)
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
- Source:
- SqlCommand.cs
使用其中一个 <CommandBehavior 给定回调过程和状态信息,并从服务器检索一个或多个结果集。
public:
IAsyncResult ^ BeginExecuteReader(AsyncCallback ^ callback, System::Object ^ stateObject, System::Data::CommandBehavior behavior);
public IAsyncResult BeginExecuteReader(AsyncCallback callback, object stateObject, System.Data.CommandBehavior behavior);
member this.BeginExecuteReader : AsyncCallback * obj * System.Data.CommandBehavior -> IAsyncResult
Public Function BeginExecuteReader (callback As AsyncCallback, stateObject As Object, behavior As CommandBehavior) As IAsyncResult
参数
- callback
- AsyncCallback
命令 AsyncCallback 执行完成后调用的委托。 通过
null (Microsoft Visual Basic 中的 Nothing) 指示不需要回调。
- stateObject
- Object
传递给回调过程的用户定义状态对象。 使用 AsyncState 属性从回调过程中检索此对象。
- behavior
- CommandBehavior
值之 CommandBehavior 一,指示语句执行和数据检索的选项。
返回
可用于轮询或等待结果或同时轮询结果的实例 IAsyncResult ;调用时 EndExecuteReader(IAsyncResult) 也需要此值,该值返回 SqlDataReader 可用于检索返回的行的实例。
例外
如果设置为 Stream ,则使用Value二进制或 VarBinary 以外的其他SqlDbType项。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
-or-
设置为
-or-
在 SqlConnection 流式处理操作期间关闭或删除。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
- or -
<xref data-throw-if-not-resolved="true" uid="Microssoft.Data.SqlClient.SqlCommand.EnableOptimizedParameterBinding"></xref>
is set to true and a parameter with direction Output or InputOutput has been added to the <xref data-throw-if-not-resolved="true" uid="Microsoft.Data.SqlClient.SqlCommand.Parameters"></xref> collection.
流式处理操作期间发生错误StreamXmlReader或TextReader对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
XmlReader TextReader流式处理操作期间关闭或Stream对象。 有关流式处理的详细信息,请参阅 SqlClient 流式处理支持。
示例
以下 Windows 应用程序演示如何使用 BeginExecuteReader 方法,以执行包含几秒钟延迟(模拟长时间运行的命令)的 Transact-SQL 语句。 由于示例以异步方式执行命令,因此窗体在等待结果时保持响应状态。 此示例将执行 SqlCommand 的对象作为 stateObject 参数传递;这样做使从回调过程中检索 SqlCommand 对象变得简单,以便代码可以调用 EndExecuteReader 与初始调用 BeginExecuteReader对应的方法。
此示例演示了许多重要的技术。 这包括从单独的线程调用与表单交互的方法。 此外,此示例演示了如何阻止用户多次并发执行命令,以及如何确保在调用回调过程之前窗体未关闭。
若要设置此示例,请创建新的 Windows 应用程序。 Button将控件、DataGridView控件和Label控件放在窗体上(接受每个控件的默认名称)。 将以下代码添加到窗体的类,根据需要修改环境的连接字符串。
此示例传递 CommandBehavior.CloseConnection 参数中的 behavior 值,导致返回 SqlDataReader 的值在关闭时自动关闭其连接。
#if NETFRAMEWORK
#nullable enable
// <Snippet1>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Data.SqlClient;
namespace SqlCommand_BeginExecuteReaderAsyncBehavior
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.label1 = new Label();
this.dataGridView1 = new DataGridView();
this.button1 = new Button();
}
private void InitializeComponent() { }
// Hook up the form's Load event handler (you can double-click on
// the form's design surface in Visual Studio), and then add
// this code to the form's class:
// You need this delegate in order to fill the grid from
// a thread other than the form's thread. See the HandleCallback
// procedure for more information.
private delegate void FillGridDelegate(SqlDataReader reader);
// You need this delegate to update the status bar.
private delegate void DisplayStatusDelegate(string Text);
// This flag ensures that the user does not attempt
// to restart the command or close the form while the
// asynchronous command is executing.
private bool isExecuting;
private Label label1 { get; set; }
private DataGridView dataGridView1 { get; set; }
private Button button1 { get; set; }
private void DisplayStatus(string Text)
{
this.label1.Text = Text;
}
private void FillGrid(SqlDataReader reader)
{
try
{
DataTable table = new DataTable();
table.Load(reader);
this.dataGridView1.DataSource = table;
DisplayStatus("Ready");
}
catch (Exception ex)
{
// Because you are guaranteed this procedure
// is running from within the form's thread,
// it can directly interact with members of the form.
DisplayStatus(string.Format("Ready (last attempt failed: {0})",
ex.Message));
}
finally
{
// Closing the reader also closes the connection,
// because this reader was created using the
// CommandBehavior.CloseConnection value.
if (reader != null)
{
reader.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;
SqlDataReader reader = command.EndExecuteReader(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. Therefore you cannot simply call code that
// fills the grid, like this:
// FillGrid(reader);
// 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.
FillGridDelegate del = new FillGridDelegate(FillGrid);
this.Invoke(del, reader);
// Do not close the reader here, because it is being used in
// a separate thread. Instead, have the procedure you have
// called close the reader once it is done with it.
}
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 there is none of
// your code 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 DisplayStatusDelegate(DisplayStatus), "Error: " +
ex.Message);
}
finally
{
isExecuting = false;
}
}
private string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks";
}
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;
SqlConnection? connection = null;
try
{
DisplayStatus("Connecting...");
connection = new SqlConnection(GetConnectionString());
// To emulate a long-running query, wait for
// a few seconds before retrieving the real data.
command = new SqlCommand("WAITFOR DELAY '0:0:5';" +
"SELECT ProductID, Name, ListPrice, Weight FROM Production.Product",
connection);
connection.Open();
DisplayStatus("Executing...");
isExecuting = true;
// Although it is not required that you pass the
// SqlCommand object as the second parameter in the
// BeginExecuteReader call, doing so makes it easier
// to call EndExecuteReader in the callback procedure.
AsyncCallback callback = new AsyncCallback(HandleCallback);
command.BeginExecuteReader(callback, command,
CommandBehavior.CloseConnection);
}
catch (Exception ex)
{
DisplayStatus("Error: " + ex.Message);
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 FormClosingEventHandler(Form1_FormClosing);
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (isExecuting)
{
MessageBox.Show(this, "Cannot close the form until " +
"the pending asynchronous command has completed. Please wait...");
e.Cancel = true;
}
}
}
}
// </Snippet1>
#endif
注解
该方法 BeginExecuteReader 启动异步执行返回行的 Transact-SQL 语句或存储过程的过程,以便其他任务在执行语句时可以并发运行。 语句完成后,开发人员必须调用 EndExecuteReader 该方法来完成操作并检索 SqlDataReader 命令返回的操作。 该方法 BeginExecuteReader 会立即返回,但在代码执行相应的 EndExecuteReader 方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。 EndExecuteReader在命令的执行完成之前调用该对象会导致SqlCommand对象阻塞,直到执行完成。
通过该 callback 参数,可以指定在 AsyncCallback 语句完成时调用的委托。 可以从此委托过程或应用程序中的任何其他位置调用 EndExecuteReader 该方法。 此外,还可以在参数中 stateObject 传递任何对象,回调过程可以使用该属性检索此信息 AsyncState 。
通过此参数 behavior ,可以指定控制命令及其连接行为的选项。 这些值可以组合在一起(使用编程语言的 Or 运算符);通常,开发人员使用 CloseConnection 该值来确保关闭时 SqlDataReader 运行时关闭连接。 开发人员还可以通过在事先知道 Transact-SQL 语句或存储过程仅返回单个行时指定SqlDataReader值来优化其行为SingleRow。
请注意,命令文本和参数将同步发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,该方法会立即返回,而无需等待来自服务器的答案,即读取是异步的。 尽管命令执行是异步的,但提取值仍然同步。 这意味着,如果需要更多数据以及基础网络的读取操作块,则调用 Read 可能会阻止。
由于回调过程从 Microsoft .NET 公共语言运行时提供的后台线程内执行,因此,必须采取严格的方法来处理应用程序中的跨线程交互。 例如,你不得从回调过程中与窗体的内容进行交互--如果必须更新窗体,则必须切换回窗体的线程才能完成工作。 本主题中的示例演示了此行为。
在执行操作期间发生的所有错误都会作为回调过程中的异常引发。 必须在回调过程中处理异常,而不是在主应用程序中处理。 有关在回调过程中处理异常的其他信息,请参阅本主题中的示例。
如果使用 ExecuteReader 或 BeginExecuteReader 访问 XML 数据,SQL Server 将返回长度大于 2,033 个字符的任何 XML 结果,每行包含 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReader 或 BeginExecuteXmlReader 读取 FOR XML 查询。
此方法忽略 CommandTimeout 属性。