SqlCommand.BeginExecuteReader Método
Definición
Importante
Parte de la información hace referencia a la versión preliminar del producto, que puede haberse modificado sustancialmente antes de lanzar la versión definitiva. Microsoft no otorga ninguna garantía, explícita o implícita, con respecto a la información proporcionada aquí.
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand y recupera uno o varios conjuntos de resultados del servidor.
Sobrecargas
BeginExecuteReader() |
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand y recupera uno o varios conjuntos de resultados del servidor. |
BeginExecuteReader(CommandBehavior) |
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand utilizando uno de los valores de CommandBehavior. |
BeginExecuteReader(AsyncCallback, Object) |
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand y recupera uno o varios conjuntos de resultados del servidor, dados un procedimiento de devolución de llamada e información de estado. |
BeginExecuteReader(AsyncCallback, Object, CommandBehavior) |
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand, utilizando uno de los valores de |
BeginExecuteReader()
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand y recupera uno o varios conjuntos de resultados del servidor.
public:
IAsyncResult ^ BeginExecuteReader();
public IAsyncResult BeginExecuteReader ();
member this.BeginExecuteReader : unit -> IAsyncResult
Public Function BeginExecuteReader () As IAsyncResult
Devoluciones
IAsyncResult que se puede utilizar para sondear y/o esperar los resultados; este valor también es necesario al invocar a EndExecuteReader(IAsyncResult), que devuelve una instancia de SqlDataReader que se puede usar para recuperar las filas devueltas.
Excepciones
Se usó un SqlDbType valor distinto de Binary o VarBinary cuando Value se estableció Streamen . Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
o bien
Un SqlDbType valor distinto de Char, NChar, NVarChar, VarChar o Xml se usó cuando Value se estableció TextReaderen .
o bien
Se usó un SqlDbType valor distinto de Xml cuando Value se estableció en XmlReader.
Cualquier error que se produjo al ejecutar el texto del comando.
o bien
Se agotó el tiempo de espera durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El par nombre/valor "Asynchronous Processing=true" no se incluyó dentro de la cadena de conexión que define la conexión para este SqlCommand.
o bien
La SqlConnection se cerró o se interrumpió durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Se produjo un error en un objeto Stream, XmlReader o TextReader durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El objeto Stream, XmlReader o TextReader se cerró durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Ejemplos
La siguiente aplicación de consola inicia el proceso de recuperación de un lector de datos de forma asincrónica. Mientras espera los resultados, esta sencilla aplicación se encuentra en un bucle, investigando el valor de la IsCompleted propiedad. Tan pronto como se haya completado el proceso, el código recupera y SqlDataReader muestra su contenido.
using System.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} ", 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.
// If you have not included "Asynchronous Processing=true" in the
// connection string, the command is not able
// to execute asynchronously.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}
}
Imports System.Data.SqlClient
Module Module1
Sub 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.
Dim commandText As String = _
"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()
End Sub
Private Sub RunCommandAsynchronously( _
ByVal commandText As String, ByVal connectionString As String)
' Given command text and connection string, asynchronously execute
' the specified command against the connection. For this example,
' the code displays an indicator as it is working, verifying the
' asynchronous behavior.
Using connection As New SqlConnection(connectionString)
Try
Dim command As New SqlCommand(commandText, connection)
connection.Open()
Dim result As IAsyncResult = command.BeginExecuteReader()
' Although it is not necessary, the following procedure
' displays a counter in the console window, indicating that
' the main thread is not blocked while awaiting the command
' results.
Dim count As Integer
While Not result.IsCompleted
count += 1
Console.WriteLine("Waiting ({0})", count)
' Wait for 1/10 second, so the counter
' does not consume all available resources
' on the main thread.
Threading.Thread.Sleep(100)
End While
' Once the IAsyncResult object signals that it is done
' waiting for results, you can retrieve the results.
Using reader As SqlDataReader = command.EndExecuteReader(result)
DisplayResults(reader)
End Using
Catch ex As SqlException
Console.WriteLine("Error ({0}): {1}", ex.Number, ex.Message)
Catch ex As InvalidOperationException
Console.WriteLine("Error: {0}", ex.Message)
Catch ex As Exception
' You might want to pass these errors
' back out to the caller.
Console.WriteLine("Error: {0}", ex.Message)
End Try
End Using
End Sub
Private Sub DisplayResults(ByVal reader As SqlDataReader)
' Display the data within the reader.
While reader.Read()
' Display all the columns.
For i As Integer = 0 To reader.FieldCount - 1
Console.Write("{0} ", reader.GetValue(i))
Next
Console.WriteLine()
End While
End Sub
Private Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
' If you have not included "Asynchronous Processing=true" in the
' connection string, the command is not able
' to execute asynchronously.
Return "Data Source=(local);Integrated Security=true;" & _
"Initial Catalog=AdventureWorks; Asynchronous Processing=true"
End Function
End Module
Comentarios
El BeginExecuteReader método inicia el proceso de ejecutar de forma asincrónica una instrucción Transact-SQL o un procedimiento almacenado que devuelve filas, de modo que otras tareas se puedan ejecutar simultáneamente mientras se ejecuta la instrucción. Una vez completada la instrucción , los desarrolladores deben llamar al EndExecuteReader método para finalizar la operación y recuperar el SqlDataReader devuelto por el comando . El BeginExecuteReader método devuelve inmediatamente, pero hasta que el código ejecuta la llamada al método correspondiente EndExecuteReader , no debe ejecutar ninguna otra llamada que inicie una ejecución sincrónica o asincrónica en el mismo SqlCommand objeto. EndExecuteReader Al llamar a antes de que se complete la ejecución del comando, el SqlCommand objeto se bloqueará hasta que finalice la ejecución.
Tenga en cuenta que el texto del comando y los parámetros se envían al servidor de forma sincrónica. Si se envía un comando grande o muchos parámetros, este método puede bloquearse durante las escrituras. Una vez enviado el comando, el método devuelve inmediatamente sin esperar una respuesta del servidor, es decir, las lecturas son asincrónicas. Aunque la ejecución de comandos es asincrónica, la captura de valores sigue siendo sincrónica. Esto significa que las llamadas a Read pueden bloquearse si se necesitan más datos y los bloques de operación de lectura de la red subyacente.
Dado que esta sobrecarga no admite un procedimiento de devolución de llamada, los desarrolladores deben sondear para determinar si el comando se ha completado, mediante la IsCompleted propiedad del IAsyncResult devuelto por el BeginExecuteReader método; o esperar a que se complete uno o varios comandos mediante la AsyncWaitHandle propiedad del devuelto IAsyncResult.
Si usa ExecuteReader o BeginExecuteReader para obtener acceso a datos XML, SQL Server devolverá cualquier resultado XML superior a 2033 caracteres de longitud en varias filas de 2033 caracteres cada uno. Para evitar este comportamiento, use ExecuteXmlReader o BeginExecuteXmlReader para leer consultas FOR XML.
Este método omite la CommandTimeout propiedad .
Consulte también
- Conexión y recuperación de datos en ADO.NET
- Uso del proveedor de datos de .NET Framework para SQL Server
- Información general de ADO.NET
Se aplica a
BeginExecuteReader(CommandBehavior)
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand utilizando uno de los valores de 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
Parámetros
- behavior
- CommandBehavior
Uno de los valores de CommandBehavior, que indican las opciones para la ejecución de instrucciones y la recuperación de datos.
Devoluciones
IAsyncResult que se puede utilizar para sondear y/o esperar los resultados; este valor también es necesario al invocar a EndExecuteReader(IAsyncResult), que devuelve una instancia de SqlDataReader que se puede usar para recuperar las filas devueltas.
Excepciones
Se usó un SqlDbType valor distinto de Binary o VarBinary cuando Value se estableció Streamen . Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
o bien
Un SqlDbType valor distinto de Char, NChar, NVarChar, VarChar o Xml se usó cuando Value se estableció TextReaderen .
o bien
Se usó un SqlDbType valor distinto de Xml cuando Value se estableció en XmlReader.
Cualquier error que se produjo al ejecutar el texto del comando.
o bien
Se agotó el tiempo de espera durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El par nombre/valor "Asynchronous Processing=true" no se incluyó dentro de la cadena de conexión que define la conexión para este SqlCommand.
o bien
La SqlConnection se cerró o se interrumpió durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Se produjo un error en un objeto Stream, XmlReader o TextReader durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El objeto Stream, XmlReader o TextReader se cerró durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Ejemplos
La siguiente aplicación de consola inicia el proceso de recuperación de un lector de datos de forma asincrónica. Mientras espera los resultados, esta sencilla aplicación se encuentra en un bucle, investigando el valor de la IsCompleted propiedad. Una vez completado el proceso, el código recupera y SqlDataReader muestra su contenido.
En este ejemplo también se pasan los CommandBehavior.CloseConnection
valores y CommandBehavior.SingleRow
en el parámetro de comportamiento, lo que hace que la conexión se cierre con el devuelto SqlDataReader está cerrada y se optimice para un único resultado de fila.
using System.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.
// If you have not included "Asynchronous Processing=true" in the
// connection string, the command is not able
// to execute asynchronously.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}
}
Imports System.Data.SqlClient
Module Module1
Sub 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.
Dim commandText As String = _
"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()
End Sub
Private Sub RunCommandAsynchronously( _
ByVal commandText As String, ByVal connectionString As String)
' Given command text and connection string, asynchronously execute
' the specified command against the connection. For this example,
' the code displays an indicator as it is working, verifying the
' asynchronous behavior.
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.
Dim connection As New SqlConnection(connectionString)
Dim command As New SqlCommand(commandText, connection)
connection.Open()
Dim result As IAsyncResult = _
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.
Dim count As Integer = 0
While Not result.IsCompleted
count += 1
Console.WriteLine("Waiting ({0})", count)
' Wait for 1/10 second, so the counter
' does not consume all available resources
' on the main thread.
Threading.Thread.Sleep(100)
End While
' The "using" statement closes the SqlDataReader when it is
' done executing.
Using reader As SqlDataReader = command.EndExecuteReader(result)
DisplayResults(reader)
End Using
Catch ex As SqlException
Console.WriteLine("Error ({0}): {1}", ex.Number, ex.Message)
Catch ex As InvalidOperationException
Console.WriteLine("Error: {0}", ex.Message)
Catch ex As Exception
' You might want to pass these errors
' back out to the caller.
Console.WriteLine("Error: {0}", ex.Message)
End Try
End Sub
Private Sub DisplayResults(ByVal reader As SqlDataReader)
' Display the data within the reader.
While reader.Read()
' Display all the columns.
For i As Integer = 0 To reader.FieldCount - 1
Console.Write("{0} ", reader.GetValue(i))
Next
Console.WriteLine()
End While
End Sub
Private Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
' If you have not included "Asynchronous Processing=true" in the
' connection string, the command is not able
' to execute asynchronously.
Return "Data Source=(local);Integrated Security=true;" & _
"Initial Catalog=AdventureWorks; Asynchronous Processing=true"
End Function
End Module
Comentarios
El BeginExecuteReader método inicia el proceso de ejecutar de forma asincrónica una instrucción Transact-SQL o un procedimiento almacenado que devuelve filas, de modo que otras tareas se puedan ejecutar simultáneamente mientras se ejecuta la instrucción. Una vez completada la instrucción , los desarrolladores deben llamar al EndExecuteReader método para finalizar la operación y recuperar el SqlDataReader devuelto por el comando . El BeginExecuteReader método devuelve inmediatamente, pero hasta que el código ejecuta la llamada al método correspondiente EndExecuteReader , no debe ejecutar ninguna otra llamada que inicie una ejecución sincrónica o asincrónica en el mismo SqlCommand objeto. EndExecuteReader Al llamar a antes de que se complete la ejecución del comando, el SqlCommand objeto se bloqueará hasta que finalice la ejecución.
El behavior
parámetro permite especificar opciones que controlan el comportamiento del comando y su conexión. Estos valores se pueden combinar (mediante el operador del OR
lenguaje de programación); por lo general, los desarrolladores usan el CommandBehavior.CloseConnection
valor para asegurarse de que el tiempo de ejecución cierra la conexión cuando SqlDataReader se cierra .
Tenga en cuenta que el texto del comando y los parámetros se envían al servidor de forma sincrónica. Si se envía un comando grande o muchos parámetros, este método puede bloquearse durante las escrituras. Una vez enviado el comando, el método devuelve inmediatamente sin esperar una respuesta del servidor, es decir, las lecturas son asincrónicas. Aunque la ejecución de comandos es asincrónica, la captura de valores sigue siendo sincrónica. Esto significa que las llamadas a Read pueden bloquearse si se necesitan más datos y los bloques de operación de lectura de la red subyacente.
Dado que esta sobrecarga no admite un procedimiento de devolución de llamada, los desarrolladores deben sondear para determinar si el comando se ha completado, mediante la IsCompleted propiedad del IAsyncResult devuelto por el BeginExecuteNonQuery método; o esperar a que se complete uno o varios comandos mediante la AsyncWaitHandle propiedad del devuelto IAsyncResult.
Si usa ExecuteReader o BeginExecuteReader para obtener acceso a datos XML, SQL Server devuelve resultados XML mayores de 2033 caracteres de longitud en varias filas de 2033 caracteres cada uno. Para evitar este comportamiento, use ExecuteXmlReader o BeginExecuteXmlReader para leer consultas FOR XML.
Este método omite la CommandTimeout propiedad .
Consulte también
- Conexión y recuperación de datos en ADO.NET
- Uso del proveedor de datos de .NET Framework para SQL Server
- Información general de ADO.NET
Se aplica a
BeginExecuteReader(AsyncCallback, Object)
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand y recupera uno o varios conjuntos de resultados del servidor, dados un procedimiento de devolución de llamada e información de estado.
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
Parámetros
- callback
- AsyncCallback
Delegado AsyncCallback que se invoca cuando finaliza la ejecución del comando. Pase null
(Nothing
en Microsoft Visual Basic) para indicar que no se requiere ninguna devolución de llamada.
- stateObject
- Object
Objeto de estado definido por el usuario que se pasa al procedimiento de devolución de llamada. Recupere este objeto desde el procedimiento de devolución de llamada mediante la propiedad AsyncState.
Devoluciones
IAsyncResult que se puede utilizar para sondear y/o esperar los resultados; este valor también es necesario al invocar a EndExecuteReader(IAsyncResult), que devuelve una instancia de SqlDataReader que se puede usar para recuperar las filas devueltas.
Excepciones
Se usó un SqlDbType valor distinto de Binary o VarBinary cuando Value se estableció Streamen . Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
o bien
Se usó un SqlDbType valor distinto de Char, NChar, NVarChar, VarChar o Xml cuando Value se estableció TextReaderen .
o bien
Se usó un SqlDbType valor distinto de Xml cuando Value se estableció XmlReaderen .
Cualquier error que se produjo al ejecutar el texto del comando.
o bien
Se agotó el tiempo de espera durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El par nombre/valor "Asynchronous Processing=true" no se incluyó dentro de la cadena de conexión que define la conexión para este SqlCommand.
o bien
La SqlConnection se cerró o se interrumpió durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Se produjo un error en un objeto Stream, XmlReader o TextReader durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El objeto Stream, XmlReader o TextReader se cerró durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Ejemplos
La siguiente aplicación Windows muestra el uso del método BeginExecuteReader, que ejecuta una instrucción Transact-SQL que incluye un retraso de unos pocos segundos (emulando un comando de ejecución prolongada). Dado que el ejemplo ejecuta el comando de forma asincrónica, el formulario sigue respondiendo mientras espera los resultados. En este ejemplo se pasa el objeto en ejecución SqlCommand como stateObject
parámetro; al hacerlo, resulta sencillo recuperar el SqlCommand objeto desde dentro del procedimiento de devolución de llamada, de modo que el código pueda llamar al EndExecuteReader método correspondiente a la llamada inicial a BeginExecuteReader.
En este ejemplo se muestran muchas técnicas importantes. Esto incluye llamar a un método que interactúa con el formulario desde un subproceso independiente. Además, en este ejemplo se muestra cómo se debe impedir que los usuarios ejecuten un comando varias veces simultáneamente y cómo debe asegurarse de que el formulario no se cierra antes de llamar al procedimiento de devolución de llamada.
Para configurar este ejemplo, cree una aplicación Windows. Coloque un Button control, un DataGridView control y un Label control en el formulario (aceptando el nombre predeterminado para cada control). Agregue el código siguiente a la clase del formulario, modificando el cadena de conexión según sea necesario para el entorno.
using System.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 = false;
// Because the overloaded version of BeginExecuteReader
// demonstrated here does not allow you to have the connection
// closed automatically, this example maintains the
// connection object externally, so that it is available for closing.
private SqlConnection connection = null;
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
{
// Do not forget to close the connection, as well.
if (reader != null)
{
reader.Close();
}
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;
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.
// If you do not include the Asynchronous Processing=true name/value pair,
// you wo not be able to execute the command asynchronously.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}
private void 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
{
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);
}
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;
}
}
}
}
Imports System.Data.SqlClient
Public Class Form1
' 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 Sub FillGridDelegate(ByVal reader As SqlDataReader)
' You need this delegate to update the status bar.
Private Delegate Sub DisplayStatusDelegate(ByVal Text As String)
' This flag ensures that the user does not attempt
' to restart the command or close the form while the
' asynchronous command is executing.
Private isExecuting As Boolean
' Because the overloaded version of BeginExecuteReader
' demonstrated here does not allow you to have the connection
' closed automatically, this example maintains the
' connection object externally, so that it is available for closing.
Private connection As SqlConnection
Private Sub DisplayStatus(ByVal Text As String)
Me.Label1.Text = Text
End Sub
Private Sub FillGrid(ByVal reader As SqlDataReader)
Try
Dim table As New DataTable
table.Load(reader)
Me.DataGridView1.DataSource = table
DisplayStatus("Ready")
Catch ex As Exception
' 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
' Do not forget to close the connection, as well.
If Not reader Is Nothing Then
reader.Close()
End If
If Not connection Is Nothing Then
connection.Close()
End If
End Try
End Sub
Private Sub HandleCallback(ByVal result As IAsyncResult)
Try
' Retrieve the original command object, passed
' to this procedure in the AsyncState property
' of the IAsyncResult parameter.
Dim command As SqlCommand = CType(result.AsyncState, SqlCommand)
Dim reader As SqlDataReader = 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.
Dim del As New FillGridDelegate(AddressOf FillGrid)
Me.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 ex As Exception
' Because you are now running code in a separate thread,
' if you do not handle the exception here, none of your other
' code catches the exception. Because 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:
Me.Invoke(New DisplayStatusDelegate(AddressOf DisplayStatus), _
"Error: " & ex.Message)
Finally
isExecuting = False
End Try
End Sub
Private Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
' If you do not include the Asynchronous Processing=true name/value pair,
' you wo not be able to execute the command asynchronously.
Return "Data Source=(local);Integrated Security=true;" & _
"Initial Catalog=AdventureWorks; Asynchronous Processing=true"
End Function
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
If isExecuting Then
MessageBox.Show(Me, _
"Already executing. Please wait until the current query " & _
"has completed.")
Else
Dim command As SqlCommand
Try
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.
Dim callback As New AsyncCallback(AddressOf HandleCallback)
command.BeginExecuteReader(callback, command)
Catch ex As Exception
DisplayStatus("Error: " & ex.Message)
If connection IsNot Nothing Then
connection.Close()
End If
End Try
End If
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) _
Handles Me.FormClosing
If isExecuting Then
MessageBox.Show(Me, "Cannot close the form until " & _
"the pending asynchronous command has completed. Please wait...")
e.Cancel = True
End If
End Sub
End Class
Comentarios
El BeginExecuteReader método inicia el proceso de ejecutar de forma asincrónica una instrucción Transact-SQL o un procedimiento almacenado que devuelve filas, de modo que otras tareas se puedan ejecutar simultáneamente mientras se ejecuta la instrucción. Cuando la instrucción se haya completado, los desarrolladores deben llamar al EndExecuteReader método para finalizar la operación y recuperar el SqlDataReader devuelto por el comando . El BeginExecuteReader método devuelve inmediatamente, pero hasta que el código ejecuta la llamada al método correspondiente EndExecuteReader , no debe ejecutar ninguna otra llamada que inicie una ejecución sincrónica o asincrónica en el mismo SqlCommand objeto. EndExecuteReader Al llamar a antes de que se complete la ejecución del comando, el SqlCommand objeto se bloqueará hasta que finalice la ejecución.
El callback
parámetro permite especificar un AsyncCallback delegado al que se llama cuando se ha completado la instrucción . Puede llamar al EndExecuteReader método desde dentro de este procedimiento delegado o desde cualquier otra ubicación dentro de la aplicación. Además, puede pasar cualquier objeto en el stateObject
parámetro y el procedimiento de devolución de llamada puede recuperar esta información mediante la AsyncState propiedad .
Tenga en cuenta que el texto del comando y los parámetros se envían al servidor de forma sincrónica. Si se envía un comando grande o muchos parámetros, este método puede bloquearse durante las escrituras. Una vez enviado el comando, el método devuelve inmediatamente sin esperar una respuesta del servidor, es decir, las lecturas son asincrónicas. Aunque la ejecución de comandos es asincrónica, la captura de valores sigue siendo sincrónica. Esto significa que las llamadas a Read pueden bloquearse si se requieren más datos y los bloques de operación de lectura de la red subyacente.
Dado que el procedimiento de devolución de llamada se ejecuta desde dentro de un subproceso en segundo plano proporcionado por el entorno de ejecución de Microsoft .NET, es muy importante adoptar un enfoque riguroso para controlar las interacciones entre subprocesos desde dentro de las aplicaciones. Por ejemplo, no debe interactuar con el contenido de un formulario desde el procedimiento de devolución de llamada; si tiene que actualizar el formulario, debe volver al subproceso del formulario para realizar el trabajo. En el ejemplo de este tema se muestra este comportamiento.
Todos los errores que se producen durante la ejecución de la operación se producen como excepciones en el procedimiento de devolución de llamada. Debe controlar la excepción en el procedimiento de devolución de llamada, no en la aplicación principal. Consulte el ejemplo de este tema para obtener información adicional sobre el control de excepciones en el procedimiento de devolución de llamada.
Si usa ExecuteReader o BeginExecuteReader para acceder a datos XML, SQL Server devuelve resultados XML mayores de 2033 caracteres de longitud en varias filas de 2033 caracteres cada uno. Para evitar este comportamiento, use ExecuteXmlReader o BeginExecuteXmlReader para leer consultas FOR XML.
Este método omite la CommandTimeout propiedad .
Consulte también
- Conexión y recuperación de datos en ADO.NET
- Uso del proveedor de datos de .NET Framework para SQL Server
- Información general de ADO.NET
Se aplica a
BeginExecuteReader(AsyncCallback, Object, CommandBehavior)
Inicia la ejecución asincrónica de la instrucción de Transact-SQL o del procedimiento almacenado que describe SqlCommand, utilizando uno de los valores de CommandBehavior
y recuperando uno o varios conjuntos de resultados del servidor, a partir del procedimiento de devolución de llamada e información de estado dados.
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
Parámetros
- callback
- AsyncCallback
Delegado AsyncCallback que se invoca cuando finaliza la ejecución del comando. Pase null
(Nothing
en Microsoft Visual Basic) para indicar que no se requiere ninguna devolución de llamada.
- stateObject
- Object
Objeto de estado definido por el usuario que se pasa al procedimiento de devolución de llamada. Recupere este objeto desde el procedimiento de devolución de llamada mediante la propiedad AsyncState.
- behavior
- CommandBehavior
Uno de los valores de CommandBehavior, que indican las opciones para la ejecución de instrucciones y la recuperación de datos.
Devoluciones
IAsyncResult que se puede utilizar para sondear y/o esperar los resultados; este valor también es necesario al invocar a EndExecuteReader(IAsyncResult), que devuelve una instancia de SqlDataReader que se puede usar para recuperar las filas devueltas.
Excepciones
Se usó un SqlDbType valor distinto de Binary o VarBinary cuando Value se estableció Streamen . Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
o bien
Se usó un SqlDbType valor distinto de Char, NChar, NVarChar, VarChar o Xml cuando Value se estableció TextReaderen .
o bien
Se usó un SqlDbType valor distinto de Xml cuando Value se estableció XmlReaderen .
Cualquier error que se produjo al ejecutar el texto del comando.
o bien
Se agotó el tiempo de espera durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El par nombre/valor "Asynchronous Processing=true" no se incluyó dentro de la cadena de conexión que define la conexión para este SqlCommand.
o bien
La SqlConnection se cerró o se interrumpió durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Se produjo un error en un objeto Stream, XmlReader o TextReader durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
El objeto Stream, XmlReader o TextReader se cerró durante una operación de streaming. Para obtener más información sobre el streaming, vea Compatibilidad de transmisión de datos de SqlClient.
Ejemplos
La siguiente aplicación Windows muestra el uso del método BeginExecuteReader, que ejecuta una instrucción Transact-SQL que incluye un retraso de unos pocos segundos (emulando un comando de ejecución prolongada). Dado que el ejemplo ejecuta el comando de forma asincrónica, el formulario sigue respondiendo mientras espera los resultados. En este ejemplo se pasa el objeto en SqlCommand ejecución como stateObject
parámetro; de este modo, resulta sencillo recuperar el SqlCommand objeto desde el procedimiento de devolución de llamada para que el código pueda llamar al EndExecuteReader método correspondiente a la llamada inicial a BeginExecuteReader.
En este ejemplo se muestran muchas técnicas importantes. Esto incluye llamar a un método que interactúa con el formulario desde un subproceso independiente. Además, en este ejemplo se muestra cómo se debe impedir que los usuarios ejecuten un comando varias veces simultáneamente y cómo debe asegurarse de que el formulario no se cierra antes de llamar al procedimiento de devolución de llamada.
Para configurar este ejemplo, cree una aplicación Windows. Coloque un Button control, un DataGridView control y un Label control en el formulario (aceptando el nombre predeterminado para cada control). Agregue el código siguiente a la clase del formulario, modificando el cadena de conexión según sea necesario para el entorno.
En este ejemplo se pasa el CommandBehavior.CloseConnection
valor en el behavior
parámetro , lo que hace que el devuelto SqlDataReader cierre automáticamente su conexión cuando se cierra.
using System.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.
// If you do not include the Asynchronous Processing=true name/value pair,
// you wo not be able to execute the command asynchronously.
return "Data Source=(local);Integrated Security=true;" +
"Initial Catalog=AdventureWorks; Asynchronous Processing=true";
}
private void 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;
}
}
}
}
Imports System.Data.SqlClient
Public Class Form1
' Add this code to the form's class:
' You 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 Sub FillGridDelegate(ByVal reader As SqlDataReader)
' You need this delegate to update the status bar.
Private Delegate Sub DisplayStatusDelegate(ByVal Text As String)
' This flag ensures that the user does not attempt
' to restart the command or close the form while the
' asynchronous command is executing.
Private isExecuting As Boolean
Private Sub DisplayStatus(ByVal Text As String)
Me.Label1.Text = Text
End Sub
Private Sub FillGrid(ByVal reader As SqlDataReader)
Try
Dim table As New DataTable
table.Load(reader)
Me.DataGridView1.DataSource = table
DisplayStatus("Ready")
Catch ex As Exception
' 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 IsNot Nothing Then
reader.Close()
End If
End Try
End Sub
Private Sub HandleCallback(ByVal result As IAsyncResult)
Try
' Retrieve the original command object, passed
' to this procedure in the AsyncState property
' of the IAsyncResult parameter.
Dim command As SqlCommand = CType(result.AsyncState, SqlCommand)
Dim reader As SqlDataReader = 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.
Dim del As New FillGridDelegate(AddressOf FillGrid)
Me.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 ex As Exception
' Because you are now running code in a separate thread,
' if you do not handle the exception here, none of your other
' code catches the exception. Because 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:
Me.Invoke(New DisplayStatusDelegate(AddressOf DisplayStatus), _
"Error: " & ex.Message)
Finally
isExecuting = False
End Try
End Sub
Private Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
' If you do not include the Asynchronous Processing=true name/value pair,
' you wo not be able to execute the command asynchronously.
Return "Data Source=(local);Integrated Security=true;" & _
"Initial Catalog=AdventureWorks; Asynchronous Processing=true"
End Function
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
If isExecuting Then
MessageBox.Show(Me, "Already executing. Please wait until the current query " & _
"has completed.")
Else
Dim connection As SqlConnection
Dim command As SqlCommand
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.
Dim callback As New AsyncCallback(AddressOf HandleCallback)
command.BeginExecuteReader(callback, command, _
CommandBehavior.CloseConnection)
Catch ex As Exception
DisplayStatus("Error: " & ex.Message)
If connection IsNot Nothing Then
connection.Close()
End If
End Try
End If
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If isExecuting Then
MessageBox.Show(Me, "Cannot close the form until " & _
"the pending asynchronous command has completed. Please wait...")
e.Cancel = True
End If
End Sub
End Class
Comentarios
El BeginExecuteReader método inicia el proceso de ejecutar de forma asincrónica una instrucción Transact-SQL o un procedimiento almacenado que devuelve filas, de modo que otras tareas se puedan ejecutar simultáneamente mientras se ejecuta la instrucción. Cuando la instrucción se haya completado, los desarrolladores deben llamar al EndExecuteReader método para finalizar la operación y recuperar el SqlDataReader devuelto por el comando . El BeginExecuteReader método devuelve inmediatamente, pero hasta que el código ejecuta la llamada al método correspondiente EndExecuteReader , no debe ejecutar ninguna otra llamada que inicie una ejecución sincrónica o asincrónica en el mismo SqlCommand objeto. EndExecuteReader Al llamar a antes de que se complete la ejecución del comando, el SqlCommand objeto se bloqueará hasta que finalice la ejecución.
El callback
parámetro permite especificar un AsyncCallback delegado al que se llama cuando se ha completado la instrucción . Puede llamar al EndExecuteReader método desde dentro de este procedimiento delegado o desde cualquier otra ubicación dentro de la aplicación. Además, puede pasar cualquier objeto en el stateObject
parámetro y el procedimiento de devolución de llamada puede recuperar esta información mediante la AsyncState propiedad .
El behavior
parámetro permite especificar opciones que controlan el comportamiento del comando y su conexión. Estos valores se pueden combinar (mediante el operador del Or
lenguaje de programación); por lo general, los desarrolladores usan el CloseConnection
valor para asegurarse de que el tiempo de ejecución cierra la conexión cuando SqlDataReader se cierra. Los desarrolladores también pueden optimizar el comportamiento de SqlDataReader especificando el SingleRow
valor cuando se conoce de antemano que la instrucción Transact-SQL o el procedimiento almacenado solo devuelven una sola fila.
Tenga en cuenta que el texto del comando y los parámetros se envían al servidor de forma sincrónica. Si se envía un comando grande o muchos parámetros, este método puede bloquearse durante las escrituras. Una vez enviado el comando, el método devuelve inmediatamente sin esperar una respuesta del servidor, es decir, las lecturas son asincrónicas. Aunque la ejecución de comandos es asincrónica, la captura de valores sigue siendo sincrónica. Esto significa que las llamadas a Read pueden bloquearse si se requieren más datos y los bloques de operación de lectura de la red subyacente.
Dado que el procedimiento de devolución de llamada se ejecuta desde un subproceso en segundo plano proporcionado por Common Language Runtime de Microsoft .NET, es muy importante adoptar un enfoque riguroso para controlar las interacciones entre subprocesos desde dentro de las aplicaciones. Por ejemplo, no debe interactuar con el contenido de un formulario desde el procedimiento de devolución de llamada; debe tener que actualizar el formulario, debe volver al subproceso del formulario para realizar el trabajo. En el ejemplo de este tema se muestra este comportamiento.
Todos los errores que se producen durante la ejecución de la operación se producen como excepciones en el procedimiento de devolución de llamada. Debe controlar la excepción en el procedimiento de devolución de llamada, no en la aplicación principal. Consulte el ejemplo de este tema para obtener información adicional sobre el control de excepciones en el procedimiento de devolución de llamada.
Si usa ExecuteReader o BeginExecuteReader para acceder a datos XML, SQL Server devolverá resultados XML mayores de 2033 caracteres de longitud en varias filas de 2033 caracteres cada uno. Para evitar este comportamiento, use ExecuteXmlReader o BeginExecuteXmlReader para leer consultas FOR XML.
Este método omite la CommandTimeout propiedad .
Consulte también
- Conexión y recuperación de datos en ADO.NET
- Uso del proveedor de datos de .NET Framework para SQL Server
- Información general de ADO.NET