2008-11-07 3 views
11

나는 다양한 데이터 저장소에 반대 일반적인 저장소를 작성하는 방법을 마련하기 위해 노력했습니다 :우리 모두 똑같은 IRepository를 찾고 있습니까?

public interface IRepository 
{ 
    IQueryable<T> GetAll<T>(); 
    void Save<T>(T item); 
    void Delete<T>(T item); 
} 
public class MemoryRepository : IRepository {...} 
public class SqlRepository : IRepository {...} 

나는 각각 같은 마시고 도메인 클래스에 반대하고 싶습니다.

public interface IRepository<T> 
{ 
    IQueryable<T> GetAll(); 
    void Save(T item); 
    void Delete(T item); 
} 
public class MemoryCustomerRepository : IRepository {...} 
public class SqlCustomerRepository : IRepository {...} 

내 질문 : 1) 첫 번째 방법도 가능한가 또한 각 도메인 클래스가 자신의 저장소를 가지고 비슷한 방식을 고려 중이 야? 2) 두 번째 접근법에 이점이 있습니까? 내가 RDBMS와 XmlWriter/XmlReader을 대상으로 내 자신의 매핑 프레임 워크를 쓸 때

답변

5
  1. 첫 번째 방법은, 내가 과거에 비슷한 가능했을된다. 단위 테스트를 쉽게하기 위해 이런 종류의 접근법을 사용할 수 있습니다.하지만 이제는 우리가이를 수행하기위한 우수한 OSS 도구를 가지고 있다고 생각합니다.

  2. 두 번째 방법은 현재 IBATIS.NET mappers으로 현재 사용하고있는 방법입니다. 모든 매퍼는 인터페이스를 가지고 있으며 모든 매퍼는 기본 CRUD 작업을 제공 할 수 있습니다. 도메인 클래스의 각 매퍼는 인터페이스로 표현되고 구체화 된 매퍼에 정의 된 특정 기능 (예 : SelectByLastName 또는 DeleteFromParent)을 갖습니다. 이 때문에 우리가 제안한대로 별도의 저장소를 구현할 필요가 없습니다. 우리의 구체적인 매퍼가 데이터베이스를 대상으로합니다. 유닛 테스트를 수행하기 위해 나는 Memory*Repository처럼 작동하는 메모리 내장 리포지토리를 생성하기 위해 StructureMapMoq을 사용합니다. 구현할 수있는 클래스가 적고 관리가 쉽고 전반적으로 테스트 할 수있는 방법이 적습니다. 단위 테스트에서 공유되는 데이터의 경우 각 도메인 클래스에 대해 WithXXX 메소드와 AsSomeProfile 메소드가있는 빌더 패턴을 사용합니다 (AsSomeProfile은 사전 구성된 테스트 데이터로 빌더 인스턴스를 반환합니다).

여기 난 보통 내 단위 테스트와 끝까지 무엇의 예 :

// Moq mocking the concrete PersonMapper through the IPersonMapper interface 
var personMock = new Mock<IPersonMapper>(MockBehavior.Strict); 
personMock.Expect(pm => pm.Select(It.IsAny<int>())).Returns(
    new PersonBuilder().AsMike().Build() 
); 

// StructureMap's ObjectFactory 
ObjectFactory.Inject(personMock.Object); 

// now anywhere in my actual code where an IPersonMapper instance is requested from 
// ObjectFactory, Moq will satisfy the requirement and return a Person instance 
// set with the PersonBuilder's Mike profile unit test data 
4

사실 이제 도메인 저장소가 일반적인 안 일반적인 합의가있다. 저장소는 엔티티를 지속하거나 검색 할 때 수행 할 수있는 작업을 표현해야합니다.

어떤 저장소는 읽기 전용, 일부는 쿼리 논리가 가능, 코드에 누출 ...

A가 된 IQueryable을 반환 GETALL 사용, 일부는 특정 조회를 만 (더 갱신, 삭제하지 않음)를 삽입하지 않습니다 있습니다 응용 프로그램 계층

하지만 Linq Table<T> 개체를 캡슐화하기 위해 제공하는 인터페이스를 사용하면 테스트 목적으로 메모리 구현으로 대체 할 수 있습니다.

그래서 나는 그것을 동일한 인터페이스 LINQ Table<T> 객체를주고, 그것을 ITable<T>를 호출하고 사용 내부의 특정 도메인 저장소 (하지 않고)하는 것이 좋습니다.

메모리에 ITable<T> 구현을 사용하여 특정 리포지토리를 메모리에 사용할 수 있습니다.

메모리에 ITable<T>을 구현하는 가장 간단한 방법은 List<T>을 사용하고 .AsQueryable() 확장 메소드를 사용하여 IQueryable<T> 인터페이스를 얻는 것입니다.

public class InMemoryTable<T> : ITable<T> 
{ 
    private List<T> list; 
    private IQueryable<T> queryable; 

    public InMemoryTable<T>(List<T> list) 
    { 
     this.list = list; 
     this.queryable = list.AsQueryable(); 
    } 

    public void Add(T entity) { list.Add(entity); } 
    public void Remove(T entity) { list.Remove(entity); } 

    public IEnumerator<T> GetEnumerator() { return list.GetEnumerator(); } 

    public Type ElementType { get { return queryable.ElementType; } } 
    public IQueryProvider Provider {  get { return queryable.Provider; } } 
    ... 
} 

당신은 테스트를 위해 데이터베이스의 고립에서 작동하지만 이상의 도메인 통찰력을 줄 진정한 특정 저장소에 있습니다.

2

이것은 조금 늦었지만, 코드 플렉스의 CommonLibrary.NET에서 IRepository 구현을 살펴보십시오. 꽤 좋은 기능 세트가 있습니다.

문제에 관해서는 많은 사람들이 GetAllProducts(), GetAllEmployees() 등의 메소드를 저장소의 구현에 사용하는 것을 봅니다. 이것은 중복되어 저장소가 일반화되지 않습니다. 필요한 것은 GetAll() 또는 All()입니다. 위에서 제공된 솔루션은 이름 지정 문제를 해결합니다.

이는 CommonLibrary.NET 문서를 온라인에서 가져옵니다 :

0.9.4 베타 2는 강력한 저장소 구현이있다.

* Supports all CRUD methods (Create, Retrieve, Update, Delete) 
* Supports aggregate methods Min, Max, Sum, Avg, Count 
* Supports Find methods using ICriteria<T> 
* Supports Distinct, and GroupBy 
* Supports interface IRepository<T> so you can use an In-Memory table for unit-testing 
* Supports versioning of your entities 
* Supports paging, eg. Get(page, pageSize) 
* Supports audit fields (CreateUser, CreatedDate, UpdateDate etc) 
* Supports the use of Mapper<T> so you can map any table record to some entity 
* Supports creating entities only if it isn't there already, by checking for field values. 
관련 문제