2012-04-23 8 views
7

estoy usando LINQ a Entidades y, últimamente, he encontrado que una gran cantidad de gente que recomiendan envolver el DataContext en una instrucción using así:El uso apropiado de "Uso de" declaración de DataContext

Using(DataContext db = new DataContext) { 
    var xx = db.customers; 
} 

Esto tiene sentido . Sin embargo, no estoy seguro de cómo incorporar esta práctica en mi modelo. Por ejemplo: Tengo una interfaz (vamos a llamarlo cliente) y está implementado por un repositorio de la siguiente manera:

namespace Models 
{ 
    public class rCustomer : iCustomer 
    { 

     readonly DataContext db = new DataContext(); 

     public customer getCustomer(Guid id) 
     { 
      return db.customers.SingleOrDefault(por => por.id == id); 
     } 

     public iQueryable<customer> getTopCustomers() 
     { 
      return db.customers.Take(10); 
     } 

     //******************************************* 
     //more methods using db, including add, update, delete, etc. 
     //******************************************* 

    } 
} 

Entonces, para tomar la ventaja de usar, que tendrá que cambiar los métodos para que parezca esto:

namespace Models 
{ 
    public class rCustomer : iCustomer 
    { 
     public customer getCustomer(Guid id) 
     { 
      using(DataContext db = new DataContext()) {  
       return db.customers.SingleOrDefault(por => por.id == id); 
      } 
     } 

     public iQueryable<customer> getTopCustomers() 
     { 
      using(DataContext db = new DataContext()) {  
       return db.customers.Take(10); 
      } 
     } 

     //******************************************* 
     //more methods using db 
     //******************************************* 

    } 
} 

Mi pregunta es: la recomendación de utilizar “uso” es realmente tan bueno? Tenga en cuenta que este cambio será importante, tengo alrededor de 25 interfaces/combinaciones de repositorios, y cada uno tiene aproximadamente 20-25 métodos, sin mencionar la necesidad de volver a probar todo después de finalizar. ¿Hay alguna otra manera?

Gracias!

Edgar.

+0

Depende de cómo uses esa clase. – SLaks

+0

Si sabe lo que 'using' está haciendo, depende de usted decidir si es válido para usted o no. – gdoron

Respuesta

5

Puede implementar una fábrica de bases de datos que causará que su DbContext se reutilice.

Esto se puede conseguir de la siguiente manera:

clase DatabaseFactory:

public class DatabaseFactory : Disposable, IDatabaseFactory 
{ 
    private YourEntities _dataContext; 
    public YourEntities Get() 
    { 
     return _dataContext ?? (_dataContext = new YourEntities()); 
    } 
    protected override void DisposeCore() 
    { 
     if (_dataContext != null) 
      _dataContext.Dispose(); 
    } 
} 

Extracto de la clase base Repositorio:

public abstract class Repository<T> : IRepository<T> where T : class 
{ 
    private YourEntities _dataContext; 
    private readonly IDbSet<T> _dbset; 
    protected Repository(IDatabaseFactory databaseFactory) 
    { 
     DatabaseFactory = databaseFactory; 
     _dbset = DataContext.Set<T>(); 
    } 

    protected IDatabaseFactory DatabaseFactory 
    { 
     get; 
     private set; 
    } 

    protected YourEntities DataContext 
    { 
     get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); } 
    } 

clase repositorio de su tabla:

public class ApplicationRepository : Repository<YourTable>, IYourTableRepository 
{ 
    private YourEntities _dataContext; 

    protected new IDatabaseFactory DatabaseFactory 
    { 
     get; 
     private set; 
    } 

    public YourTableRepository(IDatabaseFactory databaseFactory) 
     : base(databaseFactory) 
    { 
     DatabaseFactory = databaseFactory; 
    } 

    protected new YourEntities DataContext 
    { 
     get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); } 
    } 

    } 
    public interface IYourTableRepository : IRepository<YourTable> 
    { 
    } 
} 

Esto funciona perfectamente junto con la inyección de constructor AutoFac.

2

La clase DataContext está envuelta en una instrucción Using porque implementa la interfaz IDisposable.

Interna al DataContext está utilizando objetos SqlConnection y objetos SqlCommand. Para liberar correctamente esta conexión de vuelta al grupo de conexiones Sql, deben eliminarse.

El recolector de basura eventualmente lo hará, pero tomará dos pasos debido a la forma en que se administran los objetos identificables.

Se recomienda encarecidamente que se llame a Dispose y que la instrucción Using sea una buena forma de hacerlo.

Leer estos enlaces para obtener una explicación más en profundidad:

http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe/

http://www.c-sharpcorner.com/UploadFile/DipalChoksi/UnderstandingGarbageCollectioninNETFramework11292005051110AM/UnderstandingGarbageCollectioninNETFramework.aspx

3

Teniendo en cuenta el código proporcionado veo, que esplicitly utiliza readonly DataContext db = new DataContext(); como una variable global, por lo que tener en cuenta para dicho objeto por vida junto con su duración de instancia de clase rCustomer.

Si esto es cierto, lo que puede hacer, en lugar de volver a escribir todo, se puede implementar IDisposable y en el interior Dispose() código de algo así como

private void Dispose() 
{ 
    if(db != null) 
     db.Dispose(); 
} 

Espero que esto ayude.

2

Una alternativa sería hacer que su clase rCustomer implemente IDisposable, y luego en su método Dispose, puede llamar a Dispose en su DataContext si no es nulo. Sin embargo, esto simplemente empuja el patrón Desechable de su clase rCustomer, en cualquier tipo que use rCustomer.

3

Como han mencionado otros, es importante eliminar los contextos de datos. No entraré más en eso.

veo tres posibles diseños para la clase que aseguren que los contextos se disponen:

  1. La segunda solución que usted proporciona en el que se crea un contexto de datos en el ámbito de cada método de rCustomer que lo necesita por lo que cada contexto de datos está en un bloque using.
  2. Mantenga el contexto de datos como una variable de instancia y tenga rCustomer implemente IDisposable para que cuando se disponga de rCustomer, pueda deshacerse de su contexto de datos. Esto significa que todas las instancias de rCustomer deberán envolverse en los bloques using.
  3. Pase una instancia de un contexto de datos existente en rCustomer a través de su constructor. Si haces esto, entonces rCustomer no será responsable de tirarlo, el usuario de la clase lo hará. Esto le permitiría usar un solo contexto de datos en varias instancias de rCustomer, o con varias clases diferentes que necesitan acceso al contexto de datos. Esto tiene ventajas (menos sobrecarga involucrada en la creación de nuevos contextos de datos) y desventajas (huella de memoria más grande ya que los contextos de datos tienden a guardar mucha memoria a través de cachés y similares).

Honestamente, creo que la opción # 1 es bastante buena, siempre y cuando no notes que se realiza demasiado despacio (le daría tiempo/perfil si crees que está causando problemas). Debido a la agrupación de conexiones, no debería ser tan malo. Si es así, elegiría el # 3 como mi próxima opción. # 2 no está muy atrás, pero probablemente sea un poco incómodo e inesperado para otros miembros de tu equipo (si corresponde).

Cuestiones relacionadas