c# - superado - pasando el objeto Conexión DB a métodos
que es un pool de conexiones en java (9)
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.
Me preguntaba si se recomienda pasar un objeto de conexión a la 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.
Configurar la conexión es potencialmente costoso y potencialmente agrega un viaje redondo. Entonces, de nuevo, potencialmente, el mejor diseño es pasar el objeto de conexión.
Digo potencialmente, porque si usted es una aplicación Microsoft ADO, probablemente esté usando un grupo de conexión ...
Para fines de pruebas automatizadas, generalmente es más fácil pasarlo. Esto se llama inyección de dependencia .
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.
Personalmente, trabajo para centralizar mi acceso a los datos tanto como sea posible; sin embargo, si no es posible, SIEMPRE abro una conexión nueva en las otras clases, ya que creo que hay demasiadas cosas que pueden interponerse al pasar la conexión real. objeto.
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 con la portabilidad para no pasar una conexión específica si su solución será portada a otras bases de datos (es decir, no pase una conexión Sql si planea trabajar con otras bases de datos)
Sugeriría que distinga 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.
Yo usaría la 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>
Luego puede hacer referencia desde cualquier lugar de la aplicación
Personalmente, me gusta almacenar una pila de mis conexiones abiertas actuales y transacciones en la parte superior del 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 enfáticamente que no se dejen 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 termino teniendo algo en esta línea (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
}
Personalmente, me gusta utilizar conexiones estrechamente delimitadas; á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 una sobrecarga real en este enfoque.
La principal ventaja de pasar conexiones solía ser que podía pasar la transacción; sin embargo, TransactionScope
es una forma más simple de compartir una transacción entre métodos.
Como 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).