SqlCommand.BeginExecuteReader 方法

定义

重载

BeginExecuteReader()

启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。

BeginExecuteReader(CommandBehavior)

通过使用 CommandBehavior 值之一,启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行。

BeginExecuteReader(AsyncCallback, Object)

通过使用回调过程,启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。

BeginExecuteReader(AsyncCallback, Object, CommandBehavior)

使用 之一启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行CommandBehavior 值,并在给定回调过程和状态信息的情况下从服务器检索一个或多个结果集。

BeginExecuteReader()

启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行,并将结果作为 XmlReader 对象返回。

public:
 IAsyncResult ^ BeginExecuteReader();
public IAsyncResult BeginExecuteReader ();
member this.BeginExecuteReader : unit -> IAsyncResult
Public Function BeginExecuteReader () As IAsyncResult

返回

一个 IAsyncResult ,可用于轮询或等待结果,或两者兼而有之;调用时也需要此值EndExecuteXmlReader ,它返回单个 XML 值。

例外

SqlDbType当 设置为 StreamValue,使用 BinaryVarBinary 以外的 。 有关流式处理的详细信息,请参阅 SqlClient 流支持

- 或 -

SqlDbType设置为 时ValueTextReader ,使用了 CharNCharNVarCharVarCharXml 以外的其他项。

-或-

SqlDbType设置为 时ValueXmlReader ,使用了 Xml 以外的 。

执行命令文本时出现的任何错误。

- 或 -

流式处理操作期间发生了超时。 有关流式处理的详细信息,请参阅 SqlClient 流支持

流式处理操作期间关闭或删除了 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.

在流式处理操作期间, XmlReaderTextReader 对象中Stream发生错误。 有关流式处理的详细信息,请参阅 SqlClient 流支持

StreamXmlReader流式处理操作期间, 或 TextReader 对象已关闭。 有关流式处理的详细信息,请参阅 SqlClient 流支持

示例

以下控制台应用程序启动异步检索 XML 数据的过程。 在等待结果时,此简单应用程序位于循环中,调查 IsCompleted 属性值。 该过程完成后,代码将检索 XML 并显示其内容。

[!code-csharp[SqlCommand_BeginExecuteXmlReader#1] ( (~/../sqlclient/doc/samples/SqlCommand_BeginExecuteXmlReader.cs) ]

注解

方法 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

如果使用 ExecuteReaderBeginExecuteReader 访问 XML 数据,SQL Server将返回长度超过 2,033 个字符的任何 XML 结果,每行 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReaderBeginExecuteXmlReader 读取 FOR XML 查询。

此方法忽略 CommandTimeout 属性。

适用于

BeginExecuteReader(CommandBehavior)

通过使用 CommandBehavior 值之一,启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行。

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当 设置为 StreamValue,使用 BinaryVarBinary 以外的 。 有关流式处理的详细信息,请参阅 SqlClient 流支持

- 或 -

SqlDbType设置为 时ValueTextReader ,使用了 CharNCharNVarCharVarCharXml 以外的其他项。

-或-

SqlDbType设置为 时ValueXmlReader ,使用了 Xml 以外的 。

执行命令文本时出现的任何错误。

- 或 -

流式处理操作期间发生了超时。 有关流式处理的详细信息,请参阅 SqlClient 流支持

流式处理操作期间关闭或删除了 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.

在流式处理操作期间, XmlReaderTextReader 对象中Stream发生错误。 有关流式处理的详细信息,请参阅 SqlClient 流支持

StreamXmlReader流式处理操作期间, 或 TextReader 对象已关闭。 有关流式处理的详细信息,请参阅 SqlClient 流支持

示例

以下控制台应用程序将启动异步检索数据读取器的过程。 在等待结果时,此简单应用程序位于循环中,调查 IsCompleted 属性值。 该过程完成后,代码将 SqlDataReader 检索 并显示其内容。

此示例还传递 CommandBehavior.CloseConnection 行为参数中的 和 CommandBehavior.SingleRow 值,导致连接关闭,返回的 SqlDataReader 关闭,并针对单行结果进行优化。

// <Snippet1>
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";
    }
}
// </Snippet1>

注解

方法 BeginExecuteReader 启动异步执行返回行的 Transact-SQL 语句或存储过程的过程,以便其他任务可以在语句执行时并发运行。 语句完成后,开发人员必须调用 EndExecuteReader 方法来完成操作并检索 SqlDataReader 命令返回的 。 方法 BeginExecuteReader 会立即返回,但在代码执行相应的 EndExecuteReader 方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。 EndExecuteReader在命令执行完成之前调用 会导致SqlCommand对象阻塞,直到执行完成。

参数 behavior 允许你指定用于控制命令行为及其连接的选项。 可以使用编程语言的 OR 运算符) 将这些值组合在一起 (;通常,开发人员使用 CommandBehavior.CloseConnection 值来确保在 关闭 时 SqlDataReader 运行时关闭连接。

请注意,命令文本和参数以同步方式发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间阻止。 发送命令后,方法会立即返回,无需等待服务器的答案,即读取是异步的。 虽然命令执行是异步的,但值提取仍然是同步的。 这意味着,如果需要更多数据并且基础网络的读取操作阻止,则对 的调用 Read 可能会阻止。

由于此重载不支持回调过程,因此开发人员必须使用 方法返回的 的 IAsyncResult 属性轮询以确定命令是否已完成IsCompleted;或使用返回IAsyncResult的 的 属性等待一个或多个命令AsyncWaitHandle完成。BeginExecuteNonQuery

如果使用 ExecuteReaderBeginExecuteReader 访问 XML 数据,SQL Server将返回长度超过 2,033 个字符的任何 XML 结果,每行 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReaderBeginExecuteXmlReader 读取 FOR XML 查询。

此方法忽略 CommandTimeout 属性。

适用于

BeginExecuteReader(AsyncCallback, Object)

通过使用回调过程,启动此 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 ( Nothing Microsoft Visual Basic) 中指示不需要回调。

stateObject
Object

传递到回调过程的用户定义的状态对象。 使用 AsyncState 属性从回调过程内检索此对象。

返回

可用于轮询和/或等待结果的 IAsyncResult;当调用 EndExecuteXmlReader(IAsyncResult) 时,也需要该值,用于将命令的结果作为 XML 返回。

例外

SqlDbType当 设置为 StreamValue,使用 BinaryVarBinary 以外的 。 有关流式处理的详细信息,请参阅 SqlClient 流支持

- 或 -

设置为 SqlDbTypeValueTextReader ,使用了 CharNCharNVarCharVarCharXml 以外的 。

-或-

SqlDbType 设置为 XmlReaderValue,使用了 Xml 以外的 。

执行命令文本时出现的任何错误。

- 或 -

流式处理操作期间发生了超时。 有关流式处理的详细信息,请参阅 SqlClient 流支持

流式处理操作期间关闭或删除了 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.

在流式处理操作期间, XmlReaderTextReader 对象中Stream发生错误。 有关流式处理的详细信息,请参阅 SqlClient 流支持

Stream 流式处理操作期间关闭了 、 XmlReaderTextReader 对象。 有关流式处理的详细信息,请参阅 SqlClient 流支持

示例

以下 Windows 应用程序演示如何使用 BeginExecuteXmlReader 方法,以执行包含几秒钟延迟(模拟长时间运行的命令)的 Transact-SQL 语句。 此示例将正在执行 SqlCommand 的对象作为 stateObject 参数进行传递-这样做使得从回调过程中检索 SqlCommand 对象变得简单,以便代码可以调用 EndExecuteXmlReader 对应于对 的初始调用 BeginExecuteXmlReader的方法。

此示例演示了许多重要的技术。 这包括从单独的线程调用与窗体交互的方法。 此外,此示例演示了如何阻止用户多次同时执行命令,以及如何在调用回调过程之前确保窗体不会关闭。

若要设置此示例,请创建新的 Windows 应用程序。 将 Button 控件、 ListBox 控件和 Label 控件放在窗体上, (接受每个控件的默认名称) 。 将以下代码添加到窗体的 类,根据环境需要修改连接字符串。

// <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 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. 

            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 启动异步执行 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

请注意,命令文本和参数以同步方式发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间受阻。 发送命令后,方法会立即返回,而无需等待服务器的答案,即读取是异步的。

在执行操作期间发生的所有错误都将作为回调过程中的异常引发。 必须在回调过程中处理异常,而不是在主应用程序中处理。 有关在回调过程中处理异常的其他信息,请参阅本主题中的示例。

如果使用 ExecuteReaderBeginExecuteReader 访问 XML 数据,SQL Server将返回长度超过 2,033 个字符的任何 XML 结果,每行包含 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReaderBeginExecuteXmlReader 读取 FOR XML 查询。

此方法忽略 属性 CommandTimeout

另请参阅

适用于

BeginExecuteReader(AsyncCallback, Object, CommandBehavior)

使用之一启动此 SqlCommand 描述的 Transact-SQL 语句或存储过程的异步执行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 ( Nothing Microsoft Visual Basic) 中指示不需要回调。

stateObject
Object

传递到回调过程的用户定义的状态对象。 使用 AsyncState 属性从回调过程内检索此对象。

behavior
CommandBehavior

CommandBehavior 值之一,指示用于语句执行和数据检索的选项。

返回

IAsyncResult可用于轮询或等待结果或两者兼有的 ;调用 EndExecuteReader(IAsyncResult) 时也需要此值,后者返回SqlDataReader可用于检索返回的行的 实例。

例外

SqlDbType 设置为 StreamValue,使用了 BinaryVarBinary 以外的 。 有关流式处理的详细信息,请参阅 SqlClient 流支持

- 或 -

设置为 SqlDbTypeValueTextReader ,使用了 CharNCharNVarCharVarCharXml 以外的 。

-或-

SqlDbType 设置为 XmlReaderValue,使用了 Xml 以外的 。

执行命令文本时出现的任何错误。

- 或 -

流式处理操作期间发生了超时。 有关流式处理的详细信息,请参阅 SqlClient 流支持

流式处理操作期间关闭或删除了 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.

在流式处理操作期间, XmlReaderTextReader 对象中Stream发生错误。 有关流式处理的详细信息,请参阅 SqlClient 流支持

Stream 流式处理操作期间关闭了 、 XmlReaderTextReader 对象。 有关流式处理的详细信息,请参阅 SqlClient 流支持

示例

以下 Windows 应用程序演示如何使用 BeginExecuteReader 方法,以执行包含几秒钟延迟(模拟长时间运行的命令)的 Transact-SQL 语句。 由于示例以异步方式执行命令,因此窗体在等待结果时保持响应。 此示例将正在执行 SqlCommand 的对象作为 stateObject 参数传递;这样做使从回调过程中检索 SqlCommand 对象变得简单,以便代码可以调用 EndExecuteReader 对应于对 的初始调用 BeginExecuteReader的方法。

此示例演示了许多重要的技术。 这包括从单独的线程调用与窗体交互的方法。 此外,此示例还演示了如何阻止用户多次同时执行命令,以及如何在调用回调过程之前确保窗体不会关闭。

若要设置此示例,请创建新的 Windows 应用程序。 Button将控件、DataGridView控件和Label控件放在窗体上, (接受每个控件) 的默认名称。 将以下代码添加到窗体的 类,根据环境需要修改连接字符串。

此示例传递 CommandBehavior.CloseConnection 参数中的 behavior 值,导致返回的 SqlDataReader 在关闭时自动关闭其连接。

// <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 Microsoft.AdoDotNet.CodeSamples
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            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 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>

注解

方法 BeginExecuteReader 启动异步执行 Transact-SQL 语句或返回行的存储过程的过程,以便其他任务可以在语句执行时并发运行。 语句完成后,开发人员必须调用 EndExecuteReader 方法来完成操作并检索 SqlDataReader 命令返回的 。 方法 BeginExecuteReader 会立即返回,但在代码执行相应的 EndExecuteReader 方法调用之前,它不得执行针对同 SqlCommand 一对象启动同步或异步执行的任何其他调用。 在 EndExecuteReader 命令的执行完成之前调用 会导致 SqlCommand 对象阻塞,直到执行完成。

使用 callback 参数可以指定在 AsyncCallback 语句完成时调用的委托。 可以从此委托过程内或应用程序内的任何其他位置调用 EndExecuteReader 方法。 此外,可以传递 参数中的任何 stateObject 对象,并且回调过程可以使用 属性检索此信息 AsyncState

使用 behavior 参数可以指定控制命令行为及其连接的选项。 可以使用编程语言的 Or 运算符) 将这些值组合在一起 (;通常,开发人员使用 CloseConnection 值来确保在 关闭 时 SqlDataReader 运行时关闭连接。 当事先知道 Transact-SQL 语句或存储过程仅返回一行时,开发人员还可以通过指定 SingleRow 值来优化 的行为SqlDataReader

请注意,命令文本和参数以同步方式发送到服务器。 如果发送了大型命令或多个参数,此方法可能会在写入期间受阻。 发送命令后,方法会立即返回,而无需等待服务器的答案,即读取是异步的。 虽然命令执行是异步的,但值提取仍然是同步的。 这意味着,如果需要更多数据,并且基础网络的读取操作阻止,则对 的调用 Read 可能会受阻。

由于回调过程是从 Microsoft .NET 公共语言运行时提供的后台线程中执行的,因此请务必采用严格的方法来处理应用程序中的跨线程交互。 例如,您不得从回调过程中与窗体的内容进行交互 -- 如果必须更新窗体,则必须切换回窗体的线程才能完成工作。 本主题中的示例演示了此行为。

在执行操作期间发生的所有错误都将作为回调过程中的异常引发。 必须在回调过程中处理异常,而不是在主应用程序中处理。 有关在回调过程中处理异常的其他信息,请参阅本主题中的示例。

如果使用 ExecuteReaderBeginExecuteReader 访问 XML 数据,SQL Server将返回长度超过 2,033 个字符的任何 XML 结果,每行包含 2,033 个字符。 若要避免此行为,请使用 ExecuteXmlReaderBeginExecuteXmlReader 读取 FOR XML 查询。

此方法忽略 属性 CommandTimeout

适用于