2

프로젝트를 일반 저장소와 작업 단위 패턴으로 변환하기 시작했습니다. 지금까지 컨트롤러의 모든 직접 컨텍스트 참조를 일반 저장소로 리버스 엔지니어링 할 수있었습니다. 그러나, 나는 코드의 다음 두 줄에 문제가 있어요 :일반 저장소 패턴으로 변환

`context.Entry(ticket).Collection(i => i.TicketItems).Load(); 
      ticket.TicketItems.Clear();` 

이 내 컨트롤러가 TicketTicketItem 사이의 참조를 제거하기 전에 무엇을하고 있었는지입니다. TicketTicketItem 사이에는 다 대다 관계가 있습니다. 그래서이 두 줄의 코드는 내가 모든 TicketItems을 제거하기 전에 사용 된 것입니다 Ticket

답변

5

리포지토리 인터페이스의 두 가지 방법이있을 수 - 탐색 모음에 대한 탐색 참조에 대한 하나 하나

public interface IRepository<T> 
{ 
    void LoadNavigationReference<TReference>(T entity, 
     Expression<Func<T, TReference>> navigationProperty, 
     params Expression<Func<TReference, object>>[] includes) 
     where TReference : class; 

    void LoadNavigationCollection<TElement>(T entity, 
     Expression<Func<T, ICollection<TElement>>> navigationProperty, 
     params Expression<Func<TElement, object>>[] includes) 
     where TElement : class; 
} 

을 그들은 다른 중첩 된 네비게이션 속성을 포함하여 지원하기로되어 있습니다. 이 구현 될 것이다 :

public class Repository<T> : IRepository<T> 
    where T : class 
{ 
    private readonly MyContext _dbContext; 

    public Repository(MyContext dbContext) 
    { 
     _dbContext = dbContext; 
    } 

    public void LoadNavigationReference<TReference>(T entity, 
     Expression<Func<T, TReference>> navigationProperty, 
     params Expression<Func<TReference, object>>[] includes) 
     where TReference : class 
    { 
     if (includes == null || includes.Length == 0) 
      _dbContext.Entry(entity).Reference(navigationProperty).Load(); 
     else 
      _dbContext.Entry(entity).Reference(navigationProperty).Query() 
       .IncludeMultiple(includes).Load(); 
    } 

    public void LoadNavigationCollection<TElement>(T entity, 
     Expression<Func<T, ICollection<TElement>>> navigationProperty, 
     params Expression<Func<TElement, object>>[] includes) 
     where TElement : class 
    { 
     if (includes == null || includes.Length == 0) 
      _dbContext.Entry(entity).Collection(navigationProperty).Load(); 
     else 
      _dbContext.Entry(entity).Collection(navigationProperty).Query() 
       .IncludeMultiple(includes).Load(); 
    } 
} 

위에서 사용 IncludeMultiple 확장 방법 Ladislav Mrnka's answer here로부터 취해진 다.

질문의 예는 다음과 같을 것이다 :

repository.LoadNavigationCollection(ticket, i => i.TicketItems); 
ticket.TicketItems.Clear(); 

repository 유형 IRepository<Ticket>의입니다. TicketItem 다른 탐색 속성을 가지고

경우, 당신은 열심히 TicketItems와 함께이 방법을로드 할 수 TicketItemDetails 말 :

repository.LoadNavigationCollection(ticket, i => i.TicketItems, 
    t => t.TicketItemDetails); 

편집을

일반 저장소에 대한 BTW 같은 중요한 측면 참고 : 위의 코드는 실제로 16 가지 방법을 사용하는 일반 저장소의 일부이며이 스타일을 완전히 중단하고 완전히 중단하기 전에 프로젝트의 초기 단계에서 사용했습니다.

저장소에는 처음에는 약 5 가지 방법이있었습니다 (대부분의 일반적인 저장소와 마찬가지로 인터넷에서 볼 수 있습니다). Entity Framework의 많은 힘을 잃지 않고 5 가지 방법으로 만 작업하는 것은 불가능했습니다. 그래서 프로젝트의 실제 요구 사항에 따라 단계적으로 확장해야했습니다. 프로젝트에서 제거하기 전에는 "완료"되지 않았습니다.

문제는 다음과 같습니다. 누군가에게 인터페이스를 보여 주면 ("나는 여기에 훌륭한 제네릭 및 기술에 독립적 인 데이터 액세스 인터페이스가 있습니다") 즉시 "aha, 당신은 Entity Framework를 사용하고 있습니다!"라고 말합니다. 그 이유는 거의 모든 메서드가 Entity Framework 메서드에 대한 래퍼 일 뿐이며 인터페이스 메서드에 다른 이름을 사용하여이를 숨길 수 없기 때문입니다. 전체 인터페이스는 EF DbContext/Code-First의 냄새가납니다.

이제 Entity Framework가 아닌 다른 기술로 해당 인터페이스를 구현하십시오. 대부분 당신은 내가 가진 것과 같은 문제에 부딪 힐 것입니다 : 다른 기술의 힘을 이용하기 위해 많은 메소드가 빠져 있거나 기존의 메소드에 잘못된 매개 변수가 있거나 다른 메소드로 무리하게 구현할 수없는 메소드가 너무 많습니다 과학 기술.

심지어 단위 테스트를 위해 해당 인터페이스의 메모리 내장 구현을 구현하는 데 전혀 실패했습니다.

내 생각에 그런 Generic Repository는 실제 구현이 전체 인터페이스를 통해 빛나는 Leaky Abstraction의 전형적인 예입니다.

그러나 Entity Framework의 사용을 추상화 할 수없는 경우 일반 저장소 인터페이스를 만드는 것이 무의미합니다.

+0

답변과 의견을 보내 주셔서 감사합니다. 필자는이 전체적인 저장소와 작업 단위 패턴을 처음 접했지만 경험상 엔티티 프레임 워크를 직접 사용하는 것이 좋을까요? 하지만 컨트롤러를 짧게 유지하려면 어떻게해야합니까? 그렇게 많은 방법을 만들 필요가없는 한 제네릭 저장소에 집착하는 것이 좋을 것이라고 생각하십니까? – SOfanatic

+0

Repository pattern and ef.에 대한 여러분의 의견을 사랑합니다. 그냥 해달라고. 저장소는 orms가 그렇게 인기가 없었던 2004 년부터 사용되었습니다. 또한 원래의 저장소는 메소드를 찾고, 추가하고, 제거하고, 저장했습니다. –

+2

@ 루이스 : 컨트롤러에서 직접 EF와 컨텍스트를 사용하는 것은 좋지 않습니다. 우려의 분리는 좋은 습관이지만 항상 추상화를 요구하지는 않습니다. 오늘 내가하는 일은 비즈니스 로직에 초점을 맞추는 것입니다. 귀하의 예에서는 아마도 "TicketService"클래스의 일종이나 메서드 인'ClearTicket'을 가지고 있었고'ticketService.ClearTicket (ticket)'을 호출했을 것입니다. 그러나이 방법에서는 repo없이 EF를 직접 사용합니다. 데이터 액세스뿐만 아니라 컨트롤러에서 전체 비즈니스 로직을 이동시킵니다. 전체 주제는 부분적으로 미각의 문제입니다. 자신의 모범 사례를 찾아야합니다. – Slauma