2011-01-26 13 views
5

Quiero que mi Data Access Layer se construya de forma muy modular.
Por lo tanto, tengo métodos de recuperación de datos que a veces se llaman directamente desde la capa empresarial y, a veces, se llaman por otros métodos de recuperación de datos para crear dependencias de objetos.La mejor manera de tratar con la conexión de base de datos en el DAL - crear o pasar?

¿Cuál es la mejor manera de tratar con las conexiones de bases de datos en el DAL?

a) Crear una nueva conexión en cada método y disponer después.
Bueno: Fácil de escribir y trabajar.
Malo: Se están abriendo y cerrando muchas conexiones. (Rendimiento?)

b) Pasar la conexión como argumento (opcional).
bueno: pude volver a utilizar una conexión abierta para múltiples comandos.
malo: que tienen que llevar un registro de la propiedad de la conexión (que tiene que cerrarlo?) Y no se puede utilizar la muy ordenada "mediante" declaraciones.

c) ¿Algo más? (¿Conexión como singleton quizás?)

Esta es la primera vez que estoy escribiendo un DAL real, así que realmente podría necesitar ayuda de gente experimentada.

EDITAR: Como parece importar, es un proyecto de sitio web ASP.Net.

+0

Puede ser tangencial, pero FWIW, preferiría usar nhibernate y dejar que me ocupara de todo esto. es decir, simplemente trabaje con el objeto de sesión provisto por nhibernate. – Biswanath

Respuesta

5

Si está utilizando ASP.Net, la opción A es su amiga.

Cree una nueva conexión para cada solicitud, Eliminar() cuando se complete la solicitud. Asegúrese de utilizar cadenas de conexión idénticas. Las conexiones permanecerán abiertas (por defecto) y estarán disponibles a través de un grupo de conexiones.

Ver http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx para obtener más información sobre la agrupación de conexiones.

Más o menos, tiene que hacerlo de esta manera en un servidor web por lo que no tiene problemas de concurrencia de todos modos. Todo debe ser seguro para subprocesos (no tienes idea de cuántos subprocesos de trabajo simultáneos se están ejecutando en tu aplicación).

[Editado para añadir código de ejemplo]

A modo de ejemplo, aquí es lo que yo considero que es un método típico para ejecutar un procedimiento almacenado. Esto viene de un generador de código personalizado que escribí — código escrito a mano es probable que mirar un poco diferente — pero debería ser suficiente para obtener el punto de:

public int Exec( int? @iPatientID) 
{ 
    using (SqlConnection conn = new SqlConnection(this.ConnectString)) 
    using (SqlCommand  cmd = conn.CreateCommand()) 
    using (SqlDataAdapter sda = new SqlDataAdapter(cmd)) 
    { 
    cmd.CommandText = STORED_PROCEDURE_NAME ; 
    cmd.CommandType = CommandType.StoredProcedure ; 

    if (this.TimeoutInSeconds.HasValue) 
    { 
     cmd.CommandTimeout = this.TimeoutInSeconds.Value ; 
    } 

    // 
    // 1. @iPatientID 
    // 
    SqlParameter p1 = new SqlParameter(@"@iPatientID" , SqlDbType.Int) ; 
    if (@iPatientID == null) 
    { 
     p1.Value = System.DBNull.Value ; 
    } 
    else 
    { 
     p1.Value = @iPatientID ; 
    } 
    cmd.Parameters.Add(p1) ; 

    // add return code parameter 
    SqlParameter pReturnCode = new SqlParameter() ; 
    pReturnCode.SqlDbType = System.Data.SqlDbType.Int ; 
    pReturnCode.Direction = System.Data.ParameterDirection.ReturnValue ; 
    cmd.Parameters.Add(pReturnCode) ; 

    DataSet ds = new DataSet() ; 

    conn.Open() ; 
    sda.Fill(ds) ; 
    conn.Close() ; 

    this.ResultSet = (ds.Tables.Count > 0 ? ds.Tables[0] : null) ; 
    this.ReturnCode = (int) pReturnCode.Value ; 

    } 

    return this.ReturnCode ; 

} 
+0

Sí, es un sitio web de ASP.Net. Gracias por el enlace y la respuesta. Pero no entiendo cómo pasar la conexión puede ser un problema de concurrencia. – magnattic

+0

@atticae: solo se convertiría en un problema de concurrencia si el objeto de conexión termina siendo utilizado por varios subprocesos. Si esto sucede dependerá de cómo esté estructurado su código, pero es mucho menos probable que ocurra accidentalmente si está creando y eliminando la conexión dentro del contexto de un método de acceso a datos. – StriplingWarrior

+1

La única vez que desee pasar SqlConnection sería si varios métodos DAL necesitaban participar en la misma SqlTransaction. Probablemente sea mejor evitar esto. –

1

La mejor opción sería tener un pool de conexiones donde se puede obtener tus conexiones. Deje que el grupo de contactos controle la vida útil de las conexiones, ¡y obtenga las ya abiertas cuando las necesite! Un ejemplo de esto es http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx

1

utilizar los tres

conexión Escribir como parámetro opcional. Si no se pasa ninguno (nulo), cree una conexión desde alguna fuente compartida (única, tal vez) para que todas sus clases DAL estén creando conexiones con las mismas cadenas de conexión exactas (para la agrupación mencionada por @Nicholas Carey). Ábrala y ciérrela solo si la crea.

Si se transfiere una conexión, suponga que ya está abierta y no la cierre. En un nivel superior, cuando llamas a este método, puedes usar una instrucción de uso para manejar el cierre de la conexión.

2

Utilizamos una variante de la opción A.

Utilizamos realmente Marco de la entidad para que podamos aprovechar LINQ y tal. Entity Framework gestiona su propia agrupación de conexiones, por lo que crear y eliminar contextos es barato. entonces aprovechamos la inyección de dependencias para gestionar la creación real de la conexión, así:

public class MyDao 
{ 
    IFactory<MyDataContext> _contextFactory; 
    public MyDao(IFactory<MyDataContext> contextFactory) 
    { 
     _contextFactory = contextFactory; 
    } 

    public Foo GetFooById(int fooId) 
    { 
     using (var context = _contextFactory.Get()) 
     { 
      return context.Foos.Single(f => f.FooId == fooId); 
     } 
    } 
} 

De esta manera, si alguna vez decidimos que queremos crear nuestros contextos utilizando una cadena de conexión diferente, o incluso algo más complicado, simplemente podemos cambiar los enlaces de inyección de dependencia en un solo lugar, en lugar de tener que buscar cada llamada al new MyDataContext().

Cuestiones relacionadas