SqlCommand.BeginExecuteReader 方法
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
多載
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 語句或預存程式的非同步執行 |
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 設定為 Stream 時 Value ,會使用Binary或VarBinary以外的 。 如需串流的詳細資訊,請參閱 SqlClient 串流支援。
-或-
SqlDbType當 設定為 TextReader 時 Value ,使用Char、NChar、NVarChar、VarChar或Xml以外的 。
-或-
在串流作業期間已關閉或卸除的 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 串流作業期間關閉 、 XmlReader 或 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
也可以指定傳回 ntext
包含有效 XML 之資料的語句。
典型的 BeginExecuteXmlReader 查詢可以格式化為下列 C# 範例:
SqlCommand command = new SqlCommand("SELECT ContactID, FirstName, LastName FROM dbo.Contact FOR XML AUTO, XMLDATA", SqlConn);
這個方法也可以用來擷取單一資料列的單一資料行結果集。 在此情況下,如果傳回多個資料列, EndExecuteXmlReader
方法會將 附加 XmlReader 至第一個資料列的值,並捨棄結果集的其餘部分。
多個作用中結果集 (MARS) 功能可讓多個動作使用相同的連線。
請注意,命令文字和參數會同步傳送至伺服器。 如果傳送大型命令或許多參數,這個方法可能會在寫入期間封鎖。 傳送命令之後,方法會立即傳回,而不需要等候來自伺服器的答案,也就是讀取是非同步。 雖然命令執行是非同步,但值擷取仍然為同步。
因為這個多載不支援回呼程式,所以開發人員需要輪詢以判斷命令是否已完成,使用 IsCompleted 方法所 BeginExecuteXmlReader 傳回的 IAsyncResult 屬性,或等候使用 AsyncWaitHandle 所 IAsyncResult 傳回 的 屬性完成一或多個命令。
如果您使用 ExecuteReader 或 BeginExecuteReader 來存取 XML 資料,SQL Server會以 2,033 個字元的多個資料列傳回長度大於 2,033 個字元的任何 XML 結果。 若要避免這種行為,請使用 ExecuteXmlReader 或 BeginExecuteXmlReader 來讀取 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 設定為 Stream 時 Value ,會使用Binary或VarBinary以外的 。 如需串流的詳細資訊,請參閱 SqlClient 串流支援。
-或-
SqlDbType當 設定為 TextReader 時 Value ,使用Char、NChar、NVarChar、VarChar或Xml以外的 。
-或-
在串流作業期間已關閉或卸除的 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 串流作業期間關閉 、 XmlReader 或 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 可能會封鎖。
因為這個多載不支援回呼程式,所以開發人員必須輪詢以判斷命令是否已完成,並使用 IsCompleted 方法傳 BeginExecuteNonQuery 回的 IAsyncResult 屬性,或等候使用所 IAsyncResult 傳回 的 屬性完成一或多個命令 AsyncWaitHandle 。
如果您使用 ExecuteReader 或 BeginExecuteReader 來存取 XML 資料,SQL Server會以 2,033 個字元的多個資料列傳回長度大於 2,033 個字元的任何 XML 結果。 若要避免這種行為,請使用 ExecuteXmlReader 或 BeginExecuteXmlReader 來讀取 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,可用於輪詢或等待結果 (或兩者);此外,呼叫會以 XML 傳回命令結果的 EndExecuteXmlReader(IAsyncResult) 時,也需要這個值。
例外狀況
當 SqlDbType 設定為 Stream 時 Value ,會使用Binary或VarBinary以外的 。 如需串流的詳細資訊,請參閱 SqlClient 串流支援。
-或-
SqlDbType當 設定 TextReader 為 時 Value ,會使用Char、NChar、NVarChar、VarChar或Xml以外的 。
-或-
在串流作業期間已關閉或卸除的 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.
在串流作業期間, XmlReader 或 TextReader 物件中 Stream 發生錯誤。 如需串流的詳細資訊,請參閱 SqlClient 串流支援。
XmlReader在 Stream 串流作業期間,或 TextReader 物件已關閉。 如需串流的詳細資訊,請參閱 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 。
請注意,命令文字和參數會同步傳送至伺服器。 如果傳送大型命令或許多參數,這個方法可能會在寫入期間封鎖。 傳送命令之後,方法會立即傳回,而不需要等候來自伺服器的答案,也就是讀取是非同步。
在作業執行期間發生的所有錯誤都會在回呼程式中擲回為例外狀況。 您必須在回呼程式中處理例外狀況,而不是在主應用程式中。 如需在回呼程式中處理例外狀況的其他資訊,請參閱本主題中的範例。
如果您使用 ExecuteReader 或 BeginExecuteReader 存取 XML 資料,SQL Server會傳回長度大於 2,033 個字元的任何 XML 結果,每個資料列各 2,033 個字元。 若要避免這種行為,請使用 ExecuteXmlReader 或 BeginExecuteXmlReader 來讀取 FOR XML 查詢。
這個方法會 CommandTimeout 忽略 屬性。
另請參閱
適用於
BeginExecuteReader(AsyncCallback, Object, CommandBehavior)
使用下列其中一個 ,起始 Transact-SQL 語句或預存程式的 SqlCommand 非同步執行。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當 設定 Stream 為 時 Value ,使用了Binary或VarBinary以外的 。 如需串流的詳細資訊,請參閱 SqlClient 串流支援。
-或-
SqlDbType當 設定 TextReader 為 時 Value ,會使用Char、NChar、NVarChar、VarChar或Xml以外的 。
-或-
在串流作業期間已關閉或卸除的 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.
在串流作業期間, XmlReader 或 TextReader 物件中 Stream 發生錯誤。 如需串流的詳細資訊,請參閱 SqlClient 串流支援。
XmlReader在 Stream 串流作業期間,或 TextReader 物件已關閉。 如需串流的詳細資訊,請參閱 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 Common Language Runtime 所提供的背景執行緒內執行,因此您必須採取嚴格的方法來處理應用程式中的跨執行緒互動。 例如,您不得從回呼程式內與表單的內容互動,您必須更新表單,您必須切換回表單的執行緒,才能執行您的工作。 本主題中的範例示範此行為。
在作業執行期間發生的所有錯誤都會在回呼程式中擲回為例外狀況。 您必須在回呼程式中處理例外狀況,而不是在主應用程式中。 如需在回呼程式中處理例外狀況的其他資訊,請參閱本主題中的範例。
如果您使用 ExecuteReader 或 BeginExecuteReader 存取 XML 資料,SQL Server會傳回長度大於 2,033 個字元的任何 XML 結果,每個資料列各 2,033 個字元。 若要避免這種行為,請使用 ExecuteXmlReader 或 BeginExecuteXmlReader 來讀取 FOR XML 查詢。
這個方法會 CommandTimeout 忽略 屬性。