2008-10-30 23 views
21

Me pregunto si se recomienda pasar un objeto de conexión de base de datos (a otros módulos) o dejar que el método (en el otro módulo) se encargue de configurarlo. Me inclino por dejar que el método lo configure para no tener que verificar el estado de la conexión antes de usarlo, y que la persona que llama pase los datos necesarios al método de llamada que se necesitaría para configurar la conexión.pasando el objeto Conexión DB a los métodos

Respuesta

13

Personalmente me gusta usar fuertemente conexiones con alcance; ábrelos tarde, úsalos y ciérralos (en un bloque "usar", todo dentro del método local). La agrupación de conexiones se ocupará de volver a utilizar la conexión en la mayoría de los casos, por lo que no hay gastos generales reales en este enfoque.

La principal ventaja en pasar las conexiones fue para que usted pueda pasar la transacción; sin embargo, TransactionScope es una forma más simple de compartir una transacción entre métodos.

Dado que las clases son específicas de la implementación, escribiría cada una para abrir su propia transacción nativa. De lo contrario, puede usar los métodos de fábrica de ado.net para crear el tipo apropiado a partir del archivo de configuración (el nombre del proveedor).

+4

Si usa TransactionScope para compartir una transacción entre métodos que usan conexiones diferentes, la transacción se convierte en una transacción distribuida con la sobrecarga asociada. Por lo tanto, a menudo es mejor pasar una conexión (y su transacción) entre métodos, manteniendo el alcance ajustado. – Joe

+0

Esa es otra razón por la que me gusta usar TLS para este material –

+0

Esta es la manera en que generalmente lo hacemos, y de la manera que prefiero. – CSharpAtl

1

Personalmente, trabajo para centralizar mi acceso a los datos tanto como sea posible; sin embargo, si no es posible SIEMPRE abro una nueva conexión en las otras clases, ya que creo que hay demasiadas cosas que pueden interferir cuando pasando el objeto de conexión real.

0

me gustaría utilizar el web.config

<configuration> 
    <connectionStrings> 
     <add name="conn1" providerName="System.Data.SqlClient" connectionString="string here" /> 
     <add name="conn2" providerName="System.Data.SqlClient" connectionString="string here" /> 
    </connectionStrings> 
</configuration> 

A continuación, puede hacer referencia a ella desde cualquier lugar de la aplicación

+0

Pero no quiero que cada pieza tenga que obtenerlo de la configuración, tengo 1 clase que gestiona las conexiones – CSharpAtl

+0

¿Es seguro poner la cadena de conexión en el archivo de configuración sin cifrado? –

1

Configuración de la conexión es potencialmente costosa y potencialmente añade un ida y vuelta. Entonces, de nuevo, potencialmente, el mejor diseño es pasar el objeto de conexión.

digo potencialmente, porque si usted es una aplicación de Microsoft ADO, probablemente se está utilizando un pool de conexiones ....

+1

En general, la agrupación trata esto muy felizmente ... y no solo para la web. –

+0

Ok, eliminé la palabra "web" –

8

Para propósitos de prueba automatizados, por lo general es más fácil de pasar. Esto se llama dependency injection.

Cuando necesite escribir pruebas, puede crear un objeto de conexión de base de datos simulado y pasarlo en lugar del objeto real. De esta forma, sus pruebas automáticas no dependerán de una base de datos real que deba repoblarse con datos cada vez.

+1

El almacenamiento local de subprocesos resuelve esto sin necesitar dos params adicionales en cada método en la aplicación –

1

Aquí hay un poco más de información sobre este problema. Tengo una clase que maneja conexiones de DB, y tengo 2 clases que implementan una interfaz. Una de las clases es para SQL y la otra es de OLAP. El administrador es el que sabe qué conexión usar, por lo que podría pasar la conexión exacta al tipo, o el tipo puede crear su propia conexión.

1

Puede pasar objetos de conexión sin ningún problema (por ejemplo, Microsoft Enterprise Library permite el paso de llamadas a métodos estáticos en una conexión) o puede gestionarlo externamente según su diseño, no hay compensaciones técnicas directas.

Tenga cuidado para la portabilidad no pasar una conexión específica si la solución será portado a otras bases de datos (es decir, ¡No pasa un SqlConnection que va a trabajar con otras bases de datos)

9

Personalmente, me gusta almacenar una pila de mi conexión abierta actual y las transacciones en la parte superior de la Thread Local Storage usando SetData y GetData.Defino una clase que gestiona mis conexiones a la base de datos y le permite usar el patrón de disposición. Esto me ahorra la necesidad de pasar conexiones y transacciones, que es algo que creo que complica y complica el código.

Recomiendo encarecidamente contra dejándolo en manos de los métodos para abrir conexiones cada vez que necesiten datos. Llevará a una situación realmente mala en la que es difícil administrar las transacciones en toda la aplicación y se abren y cierran demasiadas conexiones (sé sobre la agrupación de conexiones, todavía es más costoso buscar una conexión desde el grupo de lo que es reutilizar un objeto)

Así que terminan por tener algo en este sentido (totalmente no probado):

class DatabaseContext : IDisposable { 

    List<DatabaseContext> currentContexts; 
    SqlConnection connection; 
    bool first = false; 

    DatabaseContext (List<DatabaseContext> contexts) 
    { 
     currentContexts = contexts; 
     if (contexts.Count == 0) 
     { 
      connection = new SqlConnection(); // fill in info 
      connection.Open(); 
      first = true; 
     } 
     else 
     { 
      connection = contexts.First().connection; 
     } 

     contexts.Add(this); 
    } 

    static List<DatabaseContext> DatabaseContexts { 
     get 
     { 
      var contexts = CallContext.GetData("contexts") as List<DatabaseContext>; 
      if (contexts == null) 
      { 
       contexts = new List<DatabaseContext>(); 
       CallContext.SetData("contexts", contexts); 
      } 
      return contexts; 
     } 
    } 

    public static DatabaseContext GetOpenConnection() 
    { 
     return new DatabaseContext(DatabaseContexts); 
    } 


    public SqlCommand CreateCommand(string sql) 
    { 
     var cmd = new SqlCommand(sql); 
     cmd.Connection = connection; 
     return cmd; 
    } 

    public void Dispose() 
    { 
     if (first) 
     { 
      connection.Close(); 
     } 
     currentContexts.Remove(this); 
    } 
} 



void Test() 
{ 
    // connection is opened here 
    using (var ctx = DatabaseContext.GetOpenConnection()) 
    { 
     using (var cmd = ctx.CreateCommand("select 1")) 
     { 
      cmd.ExecuteNonQuery(); 
     } 

     Test2(); 
    } 
    // closed after dispose 
} 

void Test2() 
{ 
    // reuse existing connection 
    using (var ctx = DatabaseContext.GetOpenConnection()) 
    { 
     using (var cmd = ctx.CreateCommand("select 2")) 
     { 
      cmd.ExecuteNonQuery(); 
     } 
    } 
    // leaves connection open 
} 
+0

Por curiosidad, ¿qué impide que la llamada Dispose() en Test2 cierre la conexión abierta en Test? Supongo que DatabaseContext debería hacer un seguimiento del número de clientes que solicitaron la conexión y solo permitir que Dispose cierre la conexión cuando solo está abierta 1 solicitud. Por lo tanto, se seguiría que Dispose también reduciría la cantidad de clientes dentro de DatabaseContext. Parece una oportunidad para el acoplamiento indebido (probablemente podría solucionarse). Además, ¿qué sucede cuando necesitas compartir un tran a través de los hilos? – xero

+0

@xero, tran a través de hilos es una condición bastante rara, por lo que se maneja manualmente.Es un juego bastante peligroso de jugar. Cuando crea un contexto, sabe si es el propietario de la conexión o no y luego dispone de acciones apropiadas –

1

sugeriría que distinguir entre el objeto de conexión y su estado (abierto, cerrado).

Puede tener un único método (o propiedad) que lea la cadena de conexión de web.config. Usar la misma versión de la cadena de conexión cada vez garantiza que se beneficiará de la agrupación de conexiones.

Llame a ese método cuando necesite abrir una conexión. En el último momento, después de configurar todas las propiedades de SqlCommand, abra la conexión, úselo y luego ciérrelo. En C#, puede usar la instrucción using para asegurarse de que la conexión esté cerrada. Si no, asegúrese de cerrar la conexión en un bloque finally.

Cuestiones relacionadas