SqlCommand.BeginExecuteReader 方法
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
多載
| 名稱 | Description |
|---|---|
| BeginExecuteReader() |
啟動非同步執行由此 SqlCommand描述的 Transact-SQL 語句或儲存程序,並從伺服器取得一個或多個結果集。 |
| BeginExecuteReader(CommandBehavior) |
啟動非同步執行由此 SqlCommand 描述的 Transact-SQL 語句或儲存程序,並使用其中一個 CommandBehavior 值。 |
| BeginExecuteReader(AsyncCallback, Object) |
啟動非同步執行由此 SqlCommand 描述的 Transact-SQL 語句或儲存程序,並以回調程序回傳結果 XmlReader 為物件。 |
| BeginExecuteReader(AsyncCallback, Object, CommandBehavior) |
啟動非同步執行由此 SqlCommand 所描述的 Transact-SQL 語句或儲存程序,使用
|
BeginExecuteReader()
啟動非同步執行由此 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當 設定為 Stream時,會使用 Value A 以外的 或VarBinary。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。 -
SqlDbType
VarCharNVarCharNCharXmlChar當 設定為 TextReader時,會使用 Value , 以外的 , 。 -
SqlDbType當 設定為 XmlReader時,會使用 Value A other than
Xml。
- 執行指令文字時發生的任何錯誤。
- 串流操作中發生了一次超時。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
- 在 SqlConnection 串流操作中關閉或掉落。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
- EnableOptimizedParameterBinding 設定為 true,且集合中新增 Parameters 了方向為 Output 或 InputOutput 的參數。
在串流操作中,物件或 發生StreamXmlReaderTextReader錯誤。 欲了解更多串流資訊,請參閱 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 字元返回任何長度超過 2,033 字元的 XML 結果。 為避免此行為,請使用 ExecuteXmlReader() 或 BeginExecuteXmlReader() 讀取 FOR XML 查詢。
此方法忽略了該 CommandTimeout 性質。
適用於
BeginExecuteReader(CommandBehavior)
啟動非同步執行由此 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當 設定為 Stream時,會使用 Value A 以外的 或VarBinary。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。 -
SqlDbType
VarCharNVarCharNCharXmlChar當 設定為 TextReader時,會使用 Value , 以外的 , 。 -
SqlDbType當 設定為 XmlReader時,會使用 Value A other than
Xml。
- 執行指令文字時發生的任何錯誤。
- 串流操作中發生了一次超時。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
- 在 SqlConnection 串流操作中關閉或掉落。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
- EnableOptimizedParameterBinding 設定為 true,且集合中新增 Parameters 了方向為 Output 或 InputOutput 的參數。
在串流操作中,物件或 發生StreamXmlReaderTextReader錯誤。 欲了解更多串流資訊,請參閱 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 字元返回任何長度超過 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(在Microsoft Visual Basic中Nothing)表示不需要回撥。
- stateObject
- Object
一個由使用者定義的狀態物件,傳遞給回調程序。 利用 プロパティ AsyncState 從回調程序中擷取此物件。
傳回
可用 IAsyncResult 來輪詢、等待結果,或兩者兼具;當呼叫 時 EndExecuteXmlReader(IAsyncResult) ,這個值也會被要求,因為指令的結果會以 XML 形式回傳。
例外狀況
當 設定為 Stream 時,會使用除 Binary 或 VarBinary 以外的 。ValueSqlDbType 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
-或者-
SqlDbType除了 Char、NChar、NVarChar、VarChar 或 Xml,當 Value 設定為 TextReader 時,會使用其他 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.
在串流操作中,物件或 發生 StreamXmlReaderTextReader 錯誤。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
Stream 該 , XmlReader 或TextReader物件在串流操作中被關閉。 欲了解更多串流資訊,請參閱 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 方法啟動非同步執行 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 字元返回任何長度超過 2,033 字元的 XML 結果。 為避免此行為,請使用 ExecuteXmlReader 或 BeginExecuteXmlReader 讀取 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(在Microsoft Visual Basic中Nothing)表示不需要回撥。
- stateObject
- Object
一個由使用者定義的狀態物件,傳遞給回調程序。 利用 プロパティ AsyncState 從回調程序中擷取此物件。
- behavior
- CommandBehavior
其中一個 CommandBehavior 值,表示語句執行與資料檢索的選項。
傳回
可用 IAsyncResult 來輪詢或等待結果,或兩者兼用;此值在呼叫 EndExecuteReader(IAsyncResult) 時也很重要,該值會回傳 SqlDataReader 一個實例,可用來檢索回傳的資料列。
例外狀況
當 設定為 Stream 時,會使用除 Binary 或 VarBinary 以外的 。ValueSqlDbType 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
-或者-
SqlDbType除了 Char、NChar、NVarChar、VarChar 或 Xml,當 Value 設定為 TextReader 時,會使用其他 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.
在串流操作中,物件或 發生 StreamXmlReaderTextReader 錯誤。 欲了解更多串流資訊,請參閱 SqlClient 串流支援。
Stream 該 , XmlReader 或TextReader物件在串流操作中被關閉。 欲了解更多串流資訊,請參閱 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 時連線關閉。 開發者也可以透過事先確定 SqlDataReader Transact-SQL 語句或儲存程序只回傳一列時指定該值來優化 的SingleRow行為。
請注意,指令文字與參數是同步傳送到伺服器的。 若傳送大型指令或多個參數,此方法可能會在寫入時阻塞。 指令發送後,方法會立即返回,無需等待伺服器回應——也就是說,讀取是非同步的。 雖然指令執行是非同步的,但取值仍然是同步的。 這表示 Read 如果需要更多資料,且底層網路的讀取操作會被阻擋,呼叫可能會被阻塞。
由於回調程序是在 Microsoft .NET 通用語言執行環境提供的背景執行緒中執行,因此你必須嚴格處理應用程式內部的跨執行緒互動。 例如,你不能在回調程序中與表單內容互動——若需要更新表單,必須切回表單的執行緒才能繼續工作。 本主題中的例子展示了這種行為。
操作執行過程中發生的所有錯誤都會在回調程序中拋出為例外。 你必須在回撥程序中處理例外,而不是在主應用程式中。 關於回調程序中處理異常的更多資訊,請參見本主題中的範例。
如果您使用 ExecuteReader 或 BeginExecuteReader 存取 XML 資料,SQL Server 會以多列 2,033 字元返回任何長度超過 2,033 字元的 XML 結果。 為避免此行為,請使用 ExecuteXmlReader 或 BeginExecuteXmlReader 讀取 FOR XML 查詢。
此方法忽略了該 CommandTimeout 性質。