[entity-framework] 저장소 패턴을 사용하지 않고 ORM을있는 그대로 사용 (EF)

저는 항상 Repository 패턴을 사용했지만 최근 프로젝트에서이 패턴과 “Unit Of Work”구현을 완벽하게 사용할 수 있는지 확인하고 싶었습니다. 땅을 파기 시작할수록 스스로에게 “정말 필요합니까?”라는 질문을하기 시작 했습니다.

이제이 모든 것은 그의 블로그에 Ayende Rahien의 게시물을 추적하여 Stackoverflow에 대한 몇 가지 의견으로 시작됩니다.

이것은 아마도 영원히 이야기 될 수 있으며 다른 응용 프로그램에 따라 다릅니다. 내가 알고 싶은 것,

  1. 이 접근 방식이 Entity Framework 프로젝트에 적합합니까?
  2. 이 접근 방식을 사용하면 비즈니스 로직이 여전히 서비스 계층 또는 확장 방법으로 이동합니까 (아래에서 설명했듯이 확장 방법은 NHib 세션을 사용하고 있음)?

확장 메서드를 사용하면 쉽게 수행 할 수 있습니다. 깨끗하고 간단하며 재사용이 가능합니다.

public static IEnumerable GetAll(
    this ISession instance, Expression<Func<T, bool>> where) where T : class
{
    return instance.QueryOver().Where(where).List();
}

이 접근 방식 Ninject을 DI로 사용 Context하여 인터페이스 를 만들고 컨트롤러에 삽입해야합니까?



답변

나는 많은 길을 갔고 다른 프로젝트에서 많은 리포지토리 구현을 만들었고 … 나는 수건을 던지고 포기했습니다. 그 이유가 여기에 있습니다.

예외에 대한 코딩

데이터베이스가 한 기술에서 다른 기술로 변경 될 확률 1 %에 대해 코딩합니까? 비즈니스의 미래 상태에 대해 생각하고 있고 예라고 대답하면 a) 다른 DB 기술로 마이그레이션 할 수있는 많은 돈이 있어야합니다. 또는 b) 재미를 위해 DB 기술을 선택하는 것입니다. ) 사용하기로 결정한 첫 번째 기술에 끔찍한 문제가 발생했습니다.

풍부한 LINQ 구문을 버리는 이유는 무엇입니까?

LINQ 및 EF는 개체 그래프를 읽고 순회하기 위해 깔끔한 작업을 수행 할 수 있도록 개발되었습니다. 동일한 유연성을 제공 할 수있는 저장소를 만들고 유지 관리하는 것은 엄청난 작업입니다. 내 경험상 저장소를 만들 때마다 쿼리의 성능을 높이거나 데이터베이스에 대한 적중 수를 줄이기 위해 항상 비즈니스 논리가 저장소 계층으로 유출되었습니다.

작성해야하는 쿼리의 모든 순열에 대한 메서드를 만들고 싶지 않습니다. 저장 프로 시저를 작성하는 것이 좋습니다. 나는 싶지 않아 GetOrder, GetOrderWithOrderItem, GetOrderWithOrderItemWithOrderActivity, GetOrderByUserId, 등 … 난 그냥 주요 기업 트래버스를 얻기 위해 원하는대로 객체 그래프를 포함 나는 그렇게하십시오.

저장소의 대부분의 예는 헛소리입니다.

블로그 나 어떤 것을 개발하지 않는 한, 리포지토리 패턴을 둘러싼 인터넷에서 찾은 예제의 90 %만큼 간단하지 않을 것입니다. 나는 이것을 충분히 강조 할 수 없다! 이것은 알아 내기 위해 진흙 속을 기어 가야하는 것입니다. 당신이 만든 완벽하게 생각한 저장소 / 솔루션을 깨뜨리는 쿼리가 항상있을 것이고, 당신이 두 번째로 스스로를 추측하고 기술적 부채 / 침식이 시작될 때까지는 아닙니다.

날 단위 테스트하지 마

하지만 리포지토리가없는 경우 단위 테스트는 어떻습니까? 어떻게 조롱합니까? 간단하지 않습니다. 두 각도에서 살펴 보겠습니다.

리포지토리 없음- 또는 다른 트릭을 DbContext사용하여 모의 할 수 IDbContext있지만 쿼리가 런타임에 결정되기 때문에 실제로는 LINQ to 개체 가 아니라 LINQ to 개체를 단위 테스트합니다 . 이제 이것을 다루는 것은 통합 테스트에 달려 있습니다.

리포지토리 사용-이제 리포지토리를 모의하고 그 사이의 계층을 단위 테스트 할 수 있습니다. 좋아요? 글쎄요 … 위의 경우 쿼리의 성능을 높이고 / 또는 데이터베이스에 대한 적중을 줄이기 위해 리포지토리 계층에 로직을 누출해야하는 경우, 단위 테스트에서 어떻게 처리 할 수 ​​있습니까? 이제 repo 레이어에 있으며 제대로 테스트하고 싶지 IQueryable<T>않습니까? 또한 솔직히 말해서 단위 테스트는 20 줄 .Where()절이 있는 쿼리를 다루지 않을 것입니다..Include()쿼리가 런타임에 생성되기 때문에 어쨌든 다른 모든 작업을 수행하기 위해 데이터베이스에 다시 연결됩니다. 또한 상위 계층 지속성을 무시하기 위해 저장소를 만들었으므로 이제 데이터베이스 기술을 변경하려는 경우 단위 테스트가 런타임에 동일한 결과를 보장하지 못해 통합 테스트로 돌아갑니다. 그래서 저장소 전체가 이상해 보입니다 ..

2 센트

일반 저장 프로 시저 (대량 삽입, 대량 삭제, CTE 등)보다 EF를 사용할 때 이미 많은 기능과 구문이 손실되었지만 C #으로 코딩도하므로 바이너리를 입력 할 필요가 없습니다. 우리는 EF를 사용하므로 다른 공급자를 사용하고 여러 가지 중에서 좋은 관련 방식으로 개체 그래프를 사용할 수 있습니다. 특정 추상화는 유용하지만 일부는 그렇지 않습니다.


답변

저장소 패턴은 추상화 입니다. 그 목적은 복잡성을 줄이고 나머지 코드를 무지하게 만드는 것입니다. 보너스 로 통합 테스트 대신 단위 테스트 를 작성할 수 있습니다 .

문제는 많은 개발자가 패턴 목적을 이해하지 못하고 호출자에게 지속성 특정 정보를 유출하는 저장소를 생성하지 못한다는 것입니다 (일반적으로 IQueryable<T>. 그렇게함으로써 그들은 OR / M을 직접 사용하는 것보다 혜택을받지 못합니다.

다른 답변을 해결하기 위해 업데이트

예외에 대한 코딩

저장소를 사용하는 것은 지속성 기술을 전환 할 수있는 것이 아닙니다 (예 : 데이터베이스 변경 또는 웹 서비스 사용 등). 복잡성과 결합을 줄이기 위해 비즈니스 로직을 지속성과 분리하는 것입니다.

단위 테스트와 통합 테스트

리포지토리에 대한 단위 테스트를 작성하지 않습니다. 기간.

그러나 리포지토리 (또는 지속성과 비즈니스 사이의 다른 추상화 계층)를 도입하여 비즈니스 논리에 대한 단위 테스트를 작성할 수 있습니다. 즉, 잘못 구성된 데이터베이스로 인해 테스트 실패에 대해 걱정할 필요가 없습니다.

쿼리에 관해서. LINQ를 사용하는 경우 리포지토리와 마찬가지로 쿼리가 작동하는지 확인해야합니다. 통합 테스트를 사용하여 수행됩니다.

차이점은 비즈니스를 LINQ 문과 혼합하지 않은 경우 실패한 것이 지속성 코드이고 다른 것이 아니라는 것을 100 % 확신 할 수 있다는 것입니다.

테스트를 분석하면 문제가 혼합되지 않은 경우 (예 : LINQ + 비즈니스 로직) 훨씬 더 깔끔하다는 것을 알 수 있습니다.

저장소 예

대부분의 예는 헛소리입니다. 그것은 매우 사실입니다. 그러나 디자인 패턴을 검색하면 많은 엉뚱한 예를 찾을 수 있습니다. 그것은 패턴 사용을 피할 이유가 아닙니다.

올바른 저장소 구현을 구축하는 것은 매우 쉽습니다. 사실, 당신은 단 하나의 규칙 만 따라야합니다 :

필요할 때까지 저장소 클래스에 아무것도 추가하지 마십시오.

코더의 많은 일반적인 저장소를 만들 게으른 시도하고 그들이 그 방법의 많은 기본 클래스를 사용할 있어야합니다. 야 그니. 리포지토리 클래스를 한 번 작성하고 응용 프로그램이 유지되는 동안 보관합니다 (년이 될 수 있음). 왜 게 으르면서 망쳐 버려. 기본 클래스 상속없이 깨끗하게 유지하십시오. 읽기 및 유지 관리가 훨씬 쉬워집니다.

(위의 진술은 지침이며 법률이 아닙니다. 기본 클래스는 동기를 부여 할 수 있습니다. 추가하기 전에 생각하여 올바른 이유에 추가하십시오)

오래된 물건

결론:

비즈니스 코드에 LINQ 문이 있거나 단위 테스트에 관심이 없다면 Entity Framework를 직접 사용하지 않을 이유가 없습니다.

최신 정보

저장소 패턴과 “추상화”가 실제로 의미하는 바에 대해 블로그를 작성했습니다. http://blog.gauffin.org/2013/01/repository-pattern-done-right/

업데이트 2

필드가 20 개 이상인 단일 항목 유형의 경우 모든 순열 조합을 지원하는 쿼리 방법을 어떻게 디자인할까요? 이름으로 만 검색을 제한하고 싶지는 않습니다. 탐색 속성으로 검색하는 것은 어떻습니까? 특정 가격 코드가있는 모든 주문 목록, 3 단계 탐색 속성 검색. IQueryable발명 된 모든 이유 는 데이터베이스에 대한 검색 조합을 구성 할 수 있기 때문입니다. 이론상 모든 것이 훌륭해 보이지만 사용자의 요구가 이론보다 우위에 있습니다.

다시 : 필드가 20 개 이상인 엔터티가 잘못 모델링되었습니다. 그것은 신의 존재입니다. 그것을 파괴.

나는 그것이 IQueryablequering을 위해 만들어진 것이 아니라고 주장하는 것이 아닙니다. 리포지토리 패턴과 같은 추상화 레이어 에는 누수가 있기 때문에 적합하지 않다는 것입니다 . 100 % 완전한 LINQ To Sql 공급자 (예 : EF)는 없습니다.

이들은 모두 eager / lazy 로딩을 사용하는 방법이나 SQL “IN”문을 수행하는 방법과 같은 구현 특정 사항을 가지고 있습니다. IQueryable저장소에 노출 되면 사용자는 이러한 모든 것을 알 수 있습니다. 따라서 데이터 소스를 추상화하려는 전체 시도는 완전한 실패입니다. OR / M을 직접 사용하는 것보다 이점을 얻지 않고 복잡성 만 추가하면됩니다.

리포지토리 패턴을 올바르게 구현하거나 아예 사용하지 마십시오.

(만약 큰 엔터티를 처리하고 싶다면 Repository 패턴을 Specification 패턴 과 결합 할 수 있습니다 . 이는 또한 테스트 가능한 완전한 추상화를 제공합니다.)


답변

IMO는 Repository추상화와 추상화 모두 UnitOfWork의미있는 개발에서 매우 가치있는 위치를 차지합니다. 사람들은 구현 세부 사항에 대해 논쟁 할 것입니다.하지만 고양이 피부를 만드는 방법이 많 듯이 추상화를 구현하는 방법도 많습니다.

귀하의 질문은 구체적으로 사용 여부와 그 이유입니다.

당신은 의심의 여지가 실현되지 것처럼 당신은 이미, 엔티티 프레임 워크에 내장 된 두 가지 패턴이 DbContext입니다 UnitOfWorkDbSet입니다 Repository. 당신은 일반적으로 단위 테스트에 필요하지 않습니다 UnitOfWork또는 Repository그들은 단순히 수업 및 기본 데이터 액세스 구현에 용이하게되어 스스로. 서비스의 논리를 단위 테스트 할 때이 두 가지 추상화를 모방하는 것이 반복해서 수행해야하는 작업입니다.

테스트를 수행하는 로직과 테스트중인 로직 사이 에 코드 종속성 레이어 (제어하지 않는) 를 추가하는 외부 라이브러리를 사용하여 모의, 가짜 또는 무엇이든 할 수 있습니다 .

작은 포인트 그래서 있다는 것입니다 에 대한 자신의 추상화를 가진 UnitOfWork하고하는 Repository단위 테스트를 조롱 할 때 최대의 제어와 유연성을 제공합니다.

모두 훌륭하지만, 이러한 추상화의 진정한 힘은 Aspect Oriented Programming 기술 을 적용 하고 SOLID 원칙을 고수 하는 간단한 방법을 제공한다는 입니다.

그래서 당신은 당신의 IRepository:

public interface IRepository<T>
    where T : class
{
    T Add(T entity);
    void Delete(T entity);
    IQueryable<T> AsQueryable();
}

그리고 그 구현 :

public class Repository<T> : IRepository<T>
    where T : class
{
    private readonly IDbSet<T> _dbSet;
    public Repository(PPContext context)
    {
        _dbSet = context.Set<T>();
    }

    public T Add(T entity)
    {
        return _dbSet.Add(entity);
    }

    public void Delete(T entity)
    {
        _dbSet.Remove(entity);
    }

    public IQueryable<T> AsQueryable()
    {
        return _dbSet.AsQueryable();
    }
}

지금까지는 평범하지 않지만 이제 로깅 데코레이터를 사용하여 로깅을 쉽게 추가하고 싶습니다 .

public class RepositoryLoggerDecorator<T> : IRepository<T>
    where T : class
{
    Logger logger = LogManager.GetCurrentClassLogger();
    private readonly IRepository<T> _decorated;
    public RepositoryLoggerDecorator(IRepository<T> decorated)
    {
        _decorated = decorated;
    }

    public T Add(T entity)
    {
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString() );
        T added = _decorated.Add(entity);
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
        return added;
    }

    public void Delete(T entity)
    {
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
        _decorated.Delete(entity);
        logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
    }

    public IQueryable<T> AsQueryable()
    {
        return _decorated.AsQueryable();
    }
}

모두 완료되었으며 기존 코드는 변경되지 않았습니다 . 예외 처리, 데이터 캐싱, 데이터 유효성 검사 등과 같이 추가 할 수있는 다른 교차 절단 문제가 많이 있으며, 설계 및 빌드 프로세스 전반에 걸쳐 기존 코드를 변경하지 않고도 간단한 기능을 추가 할 수있는 가장 가치있는 것입니다. 우리의 IRepository추상화 입니다.

이제 저는 StackOverflow에서 “멀티 테넌트 환경에서 Entity Framework가 작동하도록 만드는 방법은 무엇입니까?”라는 질문을 여러 번 보았습니다.

https://stackoverflow.com/search?q=%5Bentity-framework%5D+multi+tenant

Repository추상화 가 있다면 대답은 “데코레이터를 추가하는 것은 쉽습니다”입니다.

public class RepositoryTennantFilterDecorator<T> : IRepository<T>
    where T : class
{
    //public for Unit Test example
    public readonly IRepository<T> _decorated;
    public RepositoryTennantFilterDecorator(IRepository<T> decorated)
    {
        _decorated = decorated;
    }

    public T Add(T entity)
    {
        return _decorated.Add(entity);
    }

    public void Delete(T entity)
    {
        _decorated.Delete(entity);
    }

    public IQueryable<T> AsQueryable()
    {
        return _decorated.AsQueryable().Where(o => true);
    }
}

IMO는 항상 몇 군데 이상에서 참조되는 타사 구성 요소에 대해 간단한 추상화를 배치해야합니다. 이러한 관점에서 ORM은 우리 코드의 많은 부분에서 참조되는 완벽한 후보입니다.

누군가 “왜이 Repository라이브러리 나 타사 라이브러리에 대해 추상화 (예 :)를 가져야합니까?”라고 말할 때 일반적으로 떠오르는 대답 은 “왜 그렇지 않습니까?”입니다.

PS 데코레이터는 SimpleInjector 와 같은 IoC 컨테이너를 사용하여 적용하는 것이 매우 간단합니다 .

[TestFixture]
public class IRepositoryTesting
{
    [Test]
    public void IRepository_ContainerRegisteredWithTwoDecorators_ReturnsDecoratedRepository()
    {
        Container container = new Container();
        container.RegisterLifetimeScope<PPContext>();
        container.RegisterOpenGeneric(
            typeof(IRepository<>),
            typeof(Repository<>));
        container.RegisterDecorator(
            typeof(IRepository<>),
            typeof(RepositoryLoggerDecorator<>));
        container.RegisterDecorator(
            typeof(IRepository<>),
            typeof(RepositoryTennantFilterDecorator<>));
        container.Verify();

        using (container.BeginLifetimeScope())
        {
            var result = container.GetInstance<IRepository<Image>>();

            Assert.That(
                result,
                Is.InstanceOf(typeof(RepositoryTennantFilterDecorator<Image>)));
            Assert.That(
                (result as RepositoryTennantFilterDecorator<Image>)._decorated,
                Is.InstanceOf(typeof(RepositoryLoggerDecorator<Image>)));
        }
    }
}


답변

우선, 일부 답변에서 제안했듯이 EF 자체는 저장소 패턴이므로 저장소 이름을 지정하기 위해 추가 추상화를 만들 필요가 없습니다.

단위 테스트를위한 Mockable Repository, 정말 필요합니까?

EF는 단위 테스트에서 테스트 DB와 통신하여 SQL 테스트 DB에 대해 비즈니스 논리를 직접 테스트 할 수 있습니다. 리포지토리 패턴을 모의하는 것의 이점은 전혀 없습니다. 테스트 데이터베이스에 대해 단위 테스트를 수행하는 것이 실제로 잘못된 것은 무엇입니까? 대량 작업이 불가능하므로 원시 SQL을 작성하게됩니다. 메모리의 SQLite는 실제 데이터베이스에 대한 단위 테스트를 수행하기에 완벽한 후보입니다.

불필요한 추상화

나중에 EF를 NHbibernate 등으로 쉽게 대체 할 수 있도록 저장소를 만들고 싶습니까? 훌륭한 계획처럼 들리지만 정말 비용 효율적입니까?

Linq가 단위 테스트를 죽입니까?

나는 그것이 어떻게 죽일 수 있는지에 대한 예를보고 싶습니다.

의존성 주입, IoC

와우, 이것들은 훌륭한 단어입니다. 이론적으로는 훌륭해 보이지만 때로는 훌륭한 디자인과 훌륭한 솔루션 사이의 균형을 선택해야합니다. 우리는 그 모든 것을 사용했고 결국 모든 것을 쓰레기통에 버리고 다른 접근 방식을 선택했습니다. 크기 대 속도 (코드 크기 및 개발 속도)는 실제 생활에서 매우 중요합니다. 사용자는 유연성이 필요합니다. DI 또는 IoC 측면에서 코드가 훌륭한 디자인인지 상관하지 않습니다.

Visual Studio를 빌드하지 않는 한

많은 사람들이 개발할 Visual Studio 또는 Eclipse와 같은 복잡한 프로그램을 빌드하고 고도로 사용자 정의 할 수 있어야하는 경우 이러한 모든 훌륭한 디자인이 필요합니다. 모든 훌륭한 개발 패턴은 수년간의 개발 끝에 등장했으며 이러한 IDE는이 모든 훌륭한 디자인 패턴이 매우 중요한 곳에서 진화했습니다. 그러나 간단한 웹 기반 급여 또는 간단한 비즈니스 앱을 수행하는 경우 100 만 명의 사용자에게만 배포되는 백만 사용자를 위해 빌드하는 데 시간을 소비하는 대신 시간에 따라 개발을 진행하는 것이 좋습니다.

필터링 된보기로서의 저장소-ISecureRepository

반면에 저장소는 현재 사용자 / 역할을 기반으로 필요한 필러를 적용하여 데이터에 대한 액세스를 보호하는 EF의 필터링 된보기 여야합니다.

그러나 이렇게하면 유지 관리해야 할 거대한 코드 기반으로 끝나기 때문에 저장소가 훨씬 더 복잡해집니다. 사람들은 서로 다른 사용자 유형 또는 엔티티 유형 조합에 대해 서로 다른 저장소를 생성하게됩니다. 뿐만 아니라 우리는 많은 DTO로 끝납니다.

다음 답변은 전체 클래스 및 메서드 집합을 생성하지 않고 Filtered Repository를 구현 한 예입니다. 질문에 직접 답할 수는 없지만 도출하는 데 유용 할 수 있습니다.

면책 조항 : 저는 Entity REST SDK의 작성자입니다.

http://entityrestsdk.codeplex.com

위의 사항을 염두에두고 CRUD 작업을위한 필터를 보유하는 SecurityContext를 기반으로 필터링 된 뷰의 저장소를 생성하는 SDK를 개발했습니다. 그리고 두 종류의 규칙 만이 복잡한 작업을 단순화합니다. 첫 번째는 엔티티에 대한 액세스이고 다른 하나는 속성에 대한 읽기 / 쓰기 규칙입니다.

장점은 다른 사용자 유형에 대해 비즈니스 로직 또는 리포지토리를 다시 작성하지 않고 단순히 액세스를 차단하거나 부여 할 수 있다는 것입니다.

public class DefaultSecurityContext : BaseSecurityContext {

  public static DefaultSecurityContext Instance = new DefaultSecurityContext();

  // UserID for currently logged in User
  public static long UserID{
       get{
             return long.Parse( HttpContext.Current.User.Identity.Name );
       }
  }

  public DefaultSecurityContext(){
  }

  protected override void OnCreate(){

        // User can access his own Account only
        var acc = CreateRules<Account>();

        acc.SetRead( y => x=> x.AccountID == UserID ) ;
        acc.SetWrite( y => x=> x.AccountID == UserID );

        // User can only modify AccountName and EmailAddress fields
        acc.SetProperties( SecurityRules.ReadWrite,
              x => x.AccountName,
              x => x.EmailAddress);

        // User can read AccountType field
        acc.SetProperties<Account>( SecurityRules.Read,
              x => x.AccountType);

        // User can access his own Orders only
        var order = CreateRules<Order>();
        order.SetRead( y => x => x.CustomerID == UserID );

        // User can modify Order only if OrderStatus is not complete
        order.SetWrite( y => x => x.CustomerID == UserID
            && x.OrderStatus != "Complete" );

        // User can only modify OrderNotes and OrderStatus
        order.SetProperties( SecurityRules.ReadWrite,
              x => x.OrderNotes,
              x => x.OrderStatus );

        // User can not delete orders
        order.SetDelete(order.NotSupportedRule);
  }
}

이러한 LINQ 규칙은 모든 작업에 대해 SaveChanges 메서드의 데이터베이스에 대해 평가되며 이러한 규칙은 데이터베이스 앞에서 방화벽 역할을합니다.


답변

어떤 방법이 옳은지에 대한 많은 논쟁이 있기 때문에 둘 다 수용 가능하다고 생각하므로 내가 가장 좋아하는 것을 사용합니다 (저장소가 아닌 UoW).

EF에서 UoW는 DbContext를 통해 구현되고 DbSet은 리포지토리입니다.

데이터 레이어로 작업하는 방법은 DbContext 개체에서 직접 작업하고 복잡한 쿼리의 경우 재사용 할 수있는 쿼리에 대한 확장 메서드를 만들 것입니다.

Ayende는 CUD 작업을 추상화하는 것이 얼마나 나쁜지에 대한 게시물도 가지고 있다고 생각합니다.

나는 항상 인터페이스를 만들고 내 컨텍스트를 상속 받으므로 DI에 IoC 컨테이너를 사용할 수 있습니다.


답변

EF에 가장 많이 적용되는 것은 리포지토리 패턴이 아닙니다. 이것은 Facade 패턴입니다 (EF 메서드에 대한 호출을 더 간단하고 사용하기 쉬운 버전으로 요약).

EF는 리포지토리 패턴 (및 작업 단위 패턴)을 적용하는 것입니다. 즉, EF는 데이터 액세스 계층을 추상화하여 사용자가 SQLServer를 처리하고 있다는 것을 알지 못하도록하는 것입니다.

그리고 EF에 대한 대부분의 “리포지토리”는 동일한 서명을 갖는 지점까지도 EF의 단일 메서드에 매우 간단하게 매핑하기 때문에 좋은 외관도 아닙니다.

따라서이 소위 “리포지토리”패턴을 EF에 적용하는 두 가지 이유는보다 쉬운 테스트를 허용하고 이에 대한 “미리 준비된”호출의 하위 집합을 설정하기위한 것입니다. 그 자체로는 나쁘지 않지만 분명히 저장소는 아닙니다.


답변

Linq는 요즘 ‘Repository’입니다.

ISession + Linq는 이미 저장소이며 GetXByY메소드 나 QueryData(Query q)일반화 가 필요하지 않습니다 . DAL 사용에 약간의 편집증이 있기 때문에 여전히 저장소 인터페이스를 선호합니다. (유지 보수성의 관점에서 우리는 또한 특정 데이터 액세스 인터페이스에 대한 일부 외관을 가지고 있어야합니다).

여기에 우리가 사용하는 저장소가 있습니다. nhibernate의 직접적인 사용에서 우리를 분리하지만 linq 인터페이스를 제공합니다 (예외적 인 경우 ISession 액세스로, 결국 리팩터링 될 수 있음).

class Repo
{
    ISession _session; //via ioc
    IQueryable<T> Query()
    {
        return _session.Query<T>();
    }
}