2010-11-28 14 views
31

Nuevo en EF y he notado que usar un patrón de repositorio realmente puede simplificar las cosas y también me permitirá burlarme. Hasta aquí todo bien.Patrón de repositorio en Entity framework 4 ¿cuándo deberíamos disponer?

Mi pregunta

Un uso típico de la ObjectContext es destruir tan pronto como sea posible ver a continuación

using (var context = new SchoolEntities()) 
{  
    context.AddToDepartments(department);  
    context.SaveChanges(); 
} 

Utilizando el patrón Repositorio me he dado cuenta de que en realidad nadie usa el "Uso de patrones" por ejemplo

using (var repository= new Repository<Student>(new MyContext)) 
{  
    repository.Add(myStudentEntity) 
    repository.SaveChanges(); 
} 

¿Debería la idea ser que deberíamos deshacernos del contexto lo antes posible o la memoria podría perder o hacerse muy grande?

¿Alguien puede aclarar? Muchas gracias.

Respuesta

47

Sí, debe disponer el contexto incluso si está utilizando el repositorio. No está claro qué ventaja le proporciona la implementación de su repositorio porque todavía está proporcionando ObjectContext como parámetro del constructor, ¿verdad?

IMO el motivo principal por el que se utiliza el Repositorio y la unidad personalizada es ignorancia de persistencia = ocultar el código EF de las capas de aplicación superiores porque ObjectContext + ObjectSet en sí mismos son implementación de repositorio y patrones de unidad de trabajo.

Si utilizo el repositorio, siempre estoy envolviendo el código EF completo, por lo que la interfaz pública de mi repositorio no proporciona ninguna información sobre la infraestructura relacionada con EF. En ese caso, depende de mí cómo trato con ObjectContext.

Para simplificar los escenarios de CRUD, puedo ajustar la creación de contexto y la eliminación en cada método de depósito. En escenarios más complejos, estoy usando una clase adicional - UnitOfWork (UoW), que envuelve la creación y eliminación de contexto y desencadena cambios de guardado en la base de datos. También actúa como fábrica para todos los repositorios y pasa instancia de contexto creado a constructores de repositorios.

La mayoría de las veces estoy programando servicios o aplicaciones web, así que estoy tratando con objetos separados. Siempre estoy usando una sola instancia UoW para el procesamiento de solicitudes. Por lo tanto, la UoW se crea al comienzo del proceso de solicitud y se libera al final del proceso de solicitud. En el caso de las aplicaciones WinForms/WPF y los objetos adjuntos, creo que la buena idea es tener la instancia UoW/ObjectContext "por formulario". Hay article describiendo este enfoque con la sesión NHibernate (igual que EF ObjectContext) en la revista MSDN.

Algunos aplicación a partir de UnitOfWork y los patrones de repositorio:

titular Contexto y la fábrica abstracta para repositorios

public interface IUnitOfWork 
{ 
    IRepository<MyEntity> MyEntityRepository { get; } 
    // Repositories for other entities 

    SaveChanges(); 
} 

repositorio para entidades separadas

public interface IRepository<T> where T : class 
{ 
    IQueryable<T> GetQuery(); 
    void Insert(T entity); 
    void Delete(T entity); 

    // In very complex scenarios with big object graphs you will probably give up 
    // using detached approach and you will always load your entities from DB before 
    // deleting or updating them. In such case you will not need Update method at all. 

    void Update(T entity); 
} 

aplicación desechable de UnitOfWork envolver marco Enitity

public class UnitOfWork : IUnitOfWork, IDisposable 
{ 
    private ObjectContext _context = null; 

    public UnitOfWork(string connectionString) 
    { 
    if (String.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString"); 
    _context = new ObjectContext(connectionString); 
    } 

    private IRepository<MyEntity> _myEntityRepository; 

    public IRepository<MyEntity> MyEntityRepository 
    { 
    get 
    { 
     return _myEntityRepository ?? (_myEntityRepository = new GeneralRepository<MyEntity>(_context)); 
    } 
    } 

    public void SaveChanges() 
    { 
    _context.SaveChanges(); 
    } 

    public void Dispose() 
    { 
    Dispose(true); 
    GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
    if (disposing) 
    { 
     if (_context != null) 
     { 
     _context.Dispose(); 
     _context = null; 
     } 
    } 
    } 
} 

Base aplicación repositorio

public class GeneralRepository<T> : IRepository<T> where T : class 
{ 
    private ObjectSet<T> _set; 
    private ObjectContext _context; 


    public GeneralRepository(ObjectContext context) 
    { 
    if (context == null) throw new ArgumentNullException("context"); 
    _context = context; 
    _set = context.CreateObjectSet<T>(); 
    } 

    // Override this method for example if you need Includes 
    public virtual IQueryable<T> GetQuery() 
    { 
    return _set; 
    } 

    // Override following methods if you are working with object graphs. 
    // Methods do not execute operations in database. It is responsibility of 
    // UnitOfWork to trigger the execution 

    public virtual void Insert(T entity) 
    { 
    if (entity == null) throw new ArgumentNullException("entity"); 
    _set.AddObject(entity); 
    } 

    // These impelementations are for detached scenarios like web application 

    public virtual void Delete(T entity) 
    { 
    if (entity == null) throw new ArgumentNullException("entity"); 
    _set.Attach(entity); 
    _set.DeleteObject(entity); 
    } 

    public virtual void Update(T entity) 
    { 
    if (entity == null) throw new ArgumentNullException("entity"); 
    _set.Attach(entity); 
    _context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified); 
    } 
} 

Uso de la hora de seleccionar los datos

using (var uow = new UnitOfWork(connectionString)) 
{ 
    var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1); 
    // Do something with entity 
} 

uso cuando modifing datos

using (var uow = new UnitOfWork(connectionString)) 
{ 
    uow.MyEntitiesRepository.Update(entity); 
    uow.SaveChanges(); 
} 
+1

Fantastic.Thanks !!! el único problema que tengo con estos repositorios es que ninguno de ellos maneja la carga "Incluir" Ansioso. ¿Cómo haces ansiosa la carga con tu repositorio? – user9969

+1

Esa es la parte complicada, porque Include es una característica de EF ObjectQuery. Normalmente estoy creando un repositorio heredado de GeneralRepository y agrego las inclusiones necesarias en GetQuery modificado. Pero si necesita activar la carga ansiosa solo para algunas consultas, no lo ayudará. En ese caso, necesitas algo más. Puedo imaginar implementar algo así como LoadOptions desde Linq-To-Sql y pasar estas opciones a UnitOfWork o Repository. Luego, usar optins para configurar todo incluye. –

+2

Respuesta muy detallada: sin embargo, su clase 'UnitOfWork' tiene una sola instancia' IRepository' de ámbito local, lo que significa que la Unidad de trabajo está definiendo el repositorio con el que trabajar. Esto no es correcto. El objetivo de la Unidad de trabajo es gestionar las transacciones en varios repositorios (la UoW generalmente acepta repositorios de 1 * a través de su ctor). Esta implementación realmente no maneja eso en absoluto. Sin embargo, esto está bien para el OP. – RPM1984

Cuestiones relacionadas