Las mejores prácticas son compartir IDbConnection o cadena de conexión / fábrica en su código .Net

StackOverflow https://stackoverflow.com/questions/414207

Pregunta

Me pregunto cuál sería la mejor práctica con respecto a mantener las conexiones a la base de datos en la aplicación .Net (ADO.NET, pero creo que la práctica debería ser la misma para cualquier capa de datos). ¿Debería crear una conexión de base de datos y propagarla a lo largo de mi aplicación, o sería mejor simplemente pasar cadenas de conexión / fábricas y crear una conexión ad-hoc, cuando sea necesario?

Según entiendo, el impacto de perfomance no es significativo con la agrupación y me permite recuperarme de las conexiones rotas con bastante facilidad (solo se creará una nueva conexión) pero, de nuevo, un objeto de conexión es una abstracción y creación agradables, de nivel relativamente alto. una nueva conexión para cada operación (no el comando SQL, sino la operación de la aplicación) genera código duplicado adicional y se siente como una pérdida de tiempo / recursos (?).

¿Qué piensa acerca de estos 2 casos, cuáles son sus contras / pros y qué enfoque está utilizando en sus aplicaciones de la vida real?

Gracias

¿Fue útil?

Solución

Me encontré con la necesidad de pasar un objeto de conexión para poder permitir que varios objetos comerciales se guarden en la base de datos dentro de una sola transacción.

Si cada objeto de negocio tuviera que crear su propio SQLConnection a la base de datos, la transacción escalaría a una transacción distribuida y quería evitar eso.

No me gustaba tener que pasar el objeto SQLConnection como parámetro para guardar un objeto, así que creé un ConnectionManager que maneja la creación del objeto SQLConnection para mí, rastreando el uso del objeto SQLConnection y desconecto el objeto SQLConnection cuando no en uso.

Aquí hay un código como ejemplo del ConnectionManager:

public class ConnectionManager: IDisposable
{
    private ConnectionManager instance;

    [ThreadStatic]
    private static object lockObject; 
    private static Object LockObject
    {
        get
        {
            if (lockObject == null)
                lockObject = new object();
            return lockObject;
        }
    }

    [ThreadStatic]
    private static Dictionary<string, ConnectionManager> managers;
    private static Dictionary<string, ConnectionManager> Managers
    {
        get
        {
            if (managers == null)
                managers = new Dictionary<string, ConnectionManager>();
            return managers;
        }
    }

    private SqlConnection connection = null;
    private int referenceCount;
    private string name;


    public static ConnectionManager GetManager(string connectionName)
    {
        lock (LockObject)
        {
            ConnectionManager mgr;
            if (Managers.ContainsKey(connectionName))
            {
                mgr = Managers[connectionName];
            }
            else
            {
                mgr = new ConnectionManager(connectionName);
                Managers.Add(connectionName, mgr);
            }

            mgr.AddRef();
            return mgr;
        }
    }

    private ConnectionManager(string connectionName)
    {
        name = connectionName;
        connection = new SqlConnection(GetConnectionString(connectionName));
        connection.Open();
    }

    private string GetConnectionString(string connectionName)
    {
        string conString = Configuration.ConnectionString;
        return conString; 
    }

    public SqlConnection Connection
    {
        get { return connection; }
    }

    private void AddRef()
    {
        referenceCount += 1;
    }

    private void DeRef()
    {
        lock (LockObject)
        {
            referenceCount -= 1;
            if (referenceCount == 0)
            {
                connection.Dispose();
                Managers.Remove(name);
            }
        }
    }

#region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            DeRef();
        }
    }

    ~ConnectionManager()
    {
        Dispose(false);
    }

#endregion

}

Aquí es cómo lo usaría desde un objeto de negocio:

public void Save()
{   
    using (ConnectionManager mrg = ConnectionManager.GetManager("SQLConnectionString")
    {
        using (SQLCommand cmd = new SQLCommand)
        {
            cmd.connection = mgr.Connection
            // More ADO Code Here
        }

        _childObject.Save(); //this child object follows the same pattern with a using ConnectionManager.
    }
}

Guardo un objeto comercial y todos sus hijos se guardan también usando el mismo objeto de conexión. Cuando el alcance se aleja del padre original, la instrucción de uso cierra la conexión.

Este es un patrón que aprendí de Rocky Lhotka en su marco de CSLA.

Keith

Otros consejos

Realmente no deberías estar manejando este problema por ti mismo, ya que existen innumerables herramientas que pueden hacerlo por ti.

Si realmente desea hacerlo usted mismo, consulte el patrón de Unidad de trabajo donde puede gestionar el ciclo de vida de la conexión / transacción. Ciertamente, no desea intentar navegar por las aguas desordenadas donde hay conexiones que se abren / cierran en diferentes lugares.

Si decide dejar que sus componentes abran directamente las conexiones de db, es probable que el ciclo de vida de la conexión sea demasiado detallado y provoque muchas conexiones abiertas / cerradas para una sola operación de usuario.

El proveedor de SQL Server ADO.NET realiza la agrupación de conexiones. Puede controlar el tamaño de la agrupación mediante MinPoolSize y MaxPoolSize en la cadena de conexión.

Una cosa a tener en cuenta en su ejemplo es que las aplicaciones ASP.NET no deben usar el almacenamiento ThreadStatic, ya que un subproceso puede reutilizarse y, si no limpia todos los objetos, termina con una conexión colgada. alrededor.

En una aplicación ASP.NET, usaría la colección HttpContext.Items en su lugar. Estás implementando IDisposable, pero he visto escenarios donde los desarrolladores se olvidan de llamar a Dispose o colocar el código en un bloque de uso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top