2012-02-02 14 views
6

System.Data.SqlClient.SqlCommand tiene métodosSystem.Data.IDbCommand y ejecución asincrónica?

BeginExecuteNonQuery 
BeginExecuteReader 
BeginExecuteXmlReader 

y

EndExecuteNonQuery 
EndExecuteReader 
EndExecuteXmlReader 

para la ejecución asíncrona.

System.Data.IDbCommand Basta

ExecuteNonQuery 
ExecuteReader 
ExecuteXmlReader 

que son para operaciones síncronas solamente.

¿Hay alguna interfaz para operaciones asincrónicas?
Además, ¿por qué no hay BeginExecuteScalar?

Respuesta

1

IDbCommand no tiene el inicio/final métodos asincrónicos, ya que aún no existían en el original de .NET 1.1 lanzamiento de ADO.NET, y cuando los métodos asincrónicos fueron added in .NET 2.0, habría sido un cambio radical agregarlos a IDbCommand (agregar miembros a una interfaz es un cambio radical para los implementadores de esa interfaz).

No sé por qué BeginExecuteScalar no existe, pero se puede implementar como un método de extensión que se ajusta al BeginExecuteReader. De todos modos en .NET 4.5 ahora tenemos ExecuteScalarAsync que es más fácil de usar.

+0

No veo 'IDbCommand.ExecuteScalarAsync()'. ¿Qué [documentación] (https://msdn.microsoft.com/en-us/library/system.data.idbcommand (v = vs.110) .aspx) está mirando? – binki

+3

Oh, usted decía ['SqlCommand.ExecuteScalarAsync()'] (https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalarasync%28v=vs.110%29. aspx). Ya veo. – binki

+1

@binki o ['DbCommand.ExecuteScalarAsync()'] (https://msdn.microsoft.com/en-us/library/hh223677 (v = vs.110) .aspx), que no es tan bueno como tenerlo en la interfaz, pero admite algún tipo de polimorfismo. – phoog

-5

n no son interfaces para ellos

La razón por la que no hay un BeginExecuteScalar es porque probablemente no necesitará una llamada asincrónica para obtener un único valor de nuevo que debe ser muy rápido

+7

Ese "un valor" podría implicar 50 tablas, un par de vistas, tal vez algunos procesos almacenados, etc. Es muy probable que no sea la razón :) – Onkelborg

+0

Esa es la única razón por la que puedo darme a mí mismo y creo que es bastante resellable ... Si para obtener un valor de su db necesita involucrar 50 tablas, hay algo mal con su esquema y una llamada asincrónica no ayudará :-) –

+0

@Massimiliano Peluso: concedido en el 95% de los casos, tiene razón. Pero si tiene dicho esquema, no hay forma de cambiarlo con poca antelación, lo que solo aumenta la necesidad de un método asíncrono. –

0

Usted puede implementar el comportamiento asincrónico mediante su código personalizado, ya que no es tan complicado, como para su pregunta; no hay ninguna operación asincrónica estándar para sus objetivos.

3

En realidad, la creación de un comportamiento asíncrono equivalente a BeginExecuteNonQuery, EndExecuteNonQuery, etc. sería una tarea bastante difícil. La implementación de estas API es muy superior al simple engendrar un hilo separado, esperando la respuesta de la base de datos e invocando la devolución de llamada. Confían en la superposición de E/S y proporcionan una economía de hilos mucho mejor. No se consumen subprocesos adicionales durante la duración del salto de red, el procesamiento de la base de datos del comando, que probablemente sea el 99% del tiempo total dedicado a la llamada. Para un par de llamadas no hace la diferencia, pero cuando se diseña un servidor de alto rendimiento, la economía del hilo se vuelve muy importante.

Me preguntaba por qué falta BeginExecuteScalar. Además, la mayoría de los otros proveedores, incluido ODP.Net, por ejemplo, ¡no tienen API asíncrona en absoluto!

Y sí, no hay interfaz para operaciones asincrónicas.

1

Incluso si está recuperando "un valor" la mayor parte del tiempo se gastará en 1) salto de red al servidor de la base de datos, 2) servidor de base de datos que ejecuta el comando. Mucho más tiempo de lo que gastará, digamos leyendo 1000 registros en el conjunto de datos. Por lo tanto, estoy de acuerdo, no está claro por qué no hay BeginExecuteScalar ...

2

Para resolver exactamente este problema construí un shim que llama a los métodos asíncronos si existen en IDbConnection.IDbCommand/IDataReader o llamar a los métodos regulares si no lo hacen t.

Fuente: https://github.com/ttrider/IDbConnection-Async

NuGet: https://www.nuget.org/packages/IDbConnection-Async/

Ejemplo:

 using (IDbConnection connection = new SqlConnection(connectionString)) 
     { 
      await connection.OpenAsync(); 

      IDbCommand command = connection.CreateCommand(); 
      command.CommandText = "SELECT Name FROM Person;"; 
      using (IDataReader reader = await command.ExecuteReaderAsync()) 
      { 
       do 
       { 
        while (await reader.ReadAsync()) 
        { 
         if (!await reader.IsDBNullAsync(0)) 
         { 
          var name = reader.GetFieldValueAsync<string>(0); 
          Assert.IsNotNull(name); 
         } 
        } 
       } while (await reader.NextResultAsync()); 
      } 
     } 
1

Recomiendo tratar DbCommand y sus amigos como si fueran interfaces al consumir API de base de datos. Con el objetivo de generalizar una API sobre varios proveedores de bases de datos, DbCommand logra tan bien como IDbCommand -o, posiblemente, mejor, porque incluye las tecnologías más nuevas como await capaz Task*Async() miembros.

MS no puede agregar ningún método nuevo con nueva funcionalidad al IDbCommand. Si tuvieran que agregar un método al IDbCommand, es un cambio radical porque cualquiera es libre de implementar esa interfaz en su código y MS se ha esforzado mucho para preservar la compatibilidad ABI y API en el marco. Si expandieran las interfaces en una versión de .net, el código de cliente que funcionaba anteriormente dejaría de compilar y los ensamblados existentes que no se recompilan comenzarían a encontrar errores de tiempo de ejecución. Además, no pueden agregar los métodos adecuados *Async() o Begin*() a través de métodos de extensión sin realizar feos lanzamientos en DbCommand detrás de escena (lo cual es una mala práctica, seguridad de tipo de última hora e introducción innecesaria de tiempo de ejecución dinámico).

Por otro lado, MS puede agregar nuevos métodos virtuales a DbCommand sin romper ABI. Agregar nuevos métodos a una clase base podría considerarse romper la API (tiempo de compilación, no tan malo para romperse como tiempo de ejecución) porque si heredó DbCommand y agregó un miembro con el mismo nombre, comenzará a recibir la advertencia CS0108: 'member1' hides inherited member 'member2'. Use the new keyword if hiding was intended.) . Por lo tanto, DbCommand puede obtener las nuevas características con un impacto mínimo en el código de consumo que sigue las buenas prácticas (por ejemplo, la mayoría de las cosas seguirán funcionando siempre que no funcionen contra el sistema de tipos y métodos de llamada usando algo como myCommand.GetType().GetMethods()[3].Invoke(myCommand, …)).

Una posible estrategia que MS podría haber utilizado para ayudar a las personas que les gusta las interfaces habría sido introducir nuevas interfaces con nombres como IAsyncDbCommand y tener DbCommand implementarlos. Ellos no han hecho esto. No sé por qué, pero probablemente no lo hicieron porque aumentaría la complicación y la alternativa de consumir directamente DbCommand proporciona la mayoría de los beneficios a las interfaces consumidoras con pocas desventajas. Es decir, sería trabajo con poco rendimiento.

Cuestiones relacionadas