2010-11-28 1 views
31

EF를 처음 접하면 저장소 패턴을 사용하면 실제로 작업을 단순화 할 수 있으며 조롱 거리도 가능하다는 것을 알게되었습니다.엔티티 프레임 워크 4의 리포지토리 패턴 언제 처리해야합니까?

내 질문

된 ObjectContext의 일반적인 사용은 내가 아무도 실제로 사용 "패턴"을 사용하지 않습니다 것으로 나타났습니다 저장소 패턴을 사용

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

아래 참조 가능한 한 빨리 파괴하는 것입니다 예를 들어

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

최대한 빠른 시일 내에 컨텍스트를 삭제해야한다는 아이디어가 있어야합니까? 그렇지 않으면 메모리가 누출되거나 매우 커질 수 있습니까?

누구에게 문의 할 수 있습니까? 고마워.

답변

47

예 저장소를 사용하고 있어도 상황을 처리해야합니다. ObjectContext를 여전히 생성자의 매개 변수로 제공하고 있기 때문에 Repository 구현에서 제공하는 이점이 명확하지 않은가요?

IMO 저장소 및 사용자 지정 UnitOfWork를 사용하는 주된 이유는 ObjectContext + ObjectSet 자체가 저장소 및 작업 단위 패턴의 구현이기 때문에 상위 응용 프로그램 계층에서 persistance ignorance = hidding EF 코드입니다.

저장소를 사용할 경우 항상 전체 EF 코드를 래핑하므로 저장소의 공용 인터페이스는 EF 관련 인프라에 대한 정보를 제공하지 않습니다. 이 경우 ObjectContext를 다루는 방법은 나에게 달려있다.

간단한 직선 CRUD 시나리오를 위해 컨텍스트 생성을 마무리하고 각 저장소 방법으로 처리 할 수 ​​있습니다. 더 복잡한 시나리오에서는 컨텍스트 생성 및 폐기를 래핑하고 데이터베이스에 변경 내용을 저장하는 추가 클래스 인 UnitOfWork (UoW)를 사용하고 있습니다. 또한 모든 저장소의 팩토리 역할을하고 작성된 컨텍스트의 인스턴스를 저장소의 생성자로 전달합니다.

대부분의 경우 서비스 또는 웹 응용 프로그램을 프로그래밍하므로 분리 된 객체를 처리하고 있습니다. 나는 항상 요청 처리를 위해 단일 UoW 인스턴스를 사용하고있다. 따라서 UoW는 요청 처리 시작시 작성되고 요청 처리가 끝나면 해제됩니다. WinForms/WPF 응용 프로그램 및 첨부 된 개체의 경우 좋은 생각은 "폼 당"UoW/ObjectContext 인스턴스를 갖는 것입니다 - MSDN 매거진에서 NHibernate 세션 (EF ObjectContext와 동일)을 사용하여이 방법을 설명하는 article이 있습니다.

의 UnitOfWork 및 저장소 패턴의 일부 시작 구현 : 저장소에 대한

컨텍스트 홀더와 추상적 인 공장 분리 된 실체

에 대한

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

    SaveChanges(); 
} 

저장소

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); 
} 

의 UnitOfWork가 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; 
     } 
    } 
    } 
} 

자료 저장소 구현

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); 
    } 
} 

사용 데이터

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

Fantastic.Thanks을 modifing에 때 데이터

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

사용 을 선택! 이 리포지토리에서 내가 가진 유일한 문제는 그들 중 누구도 "Include"Eager 로딩을 처리하지 않는다는 것입니다. 저장소로 어떻게 열망합니까? – user9969

+1

Include는 EF ObjectQuery의 기능이기 때문에 까다로운 부분입니다. 저는 일반적으로 GeneralRepository에서 상속받은 저장소를 만들고 필요한 Include를 재정의 된 GetQuery에 추가합니다. 그러나 일부 쿼리에 대해서만 열기를 활성화해야하는 경우 도움이되지 않습니다. 이 경우에는 다른 것을 필요로합니다. Linq-To-SQL에서 LoadOptions를 구현하고이 옵션을 UnitOfWork 또는 Repository에 전달하는 것과 같은 것을 상상할 수 있습니다. 그런 다음 optins를 사용하여 모두 포함을 설정합니다. –

+2

아주 깊이있는 대답 - 그러나, UnitOfWork 클래스는 하나의 로컬 스코프 된 IRepository 인스턴스를 가지고 있습니다. 이것은 작업 단위가 작업 할 저장소를 정의하고 있음을 의미합니다. 이것은 정확하지 않습니다. 작업 단위 (Unit of Work)의 요점은 여러 저장소에서 트랜잭션을 처리하는 것입니다 (일반적으로 UoW는 해당 저장소를 통해 1- * 저장소를 허용합니다). 이 구현은 전혀 처리하지 않습니다. 어쩌면 이것은 OP에게는 좋을지도 모릅니다. – RPM1984