2009-11-07 4 views
3

작은 프로젝트를 위해 SQL에 Linq를 사용하려고합니다. 집에서 작업하고 있습니다. 로컬 MySQL 데이터베이스에 대해 dbmetal.exe (DBLinq 프로젝트에서)를 사용하여 컨텍스트 코드와 모든 엔티티 클래스를 생성했습니다.일반 테이블 <TEntity>

모든 것이 잘 작동하지만 일부 중복 코드를 추상화하려고 시도하고 있으며 그렇게하려고하는 문제에 직면하고 있습니다.

기본적으로 내 모든 엔티티는 내 컨텍스트 클래스에 Table<TEntity>입니다. 예를 들어 나는 Table<User>Table<Calendar>입니다.

저장소 동작을위한 다양한 인터페이스를 설계하는 동안 각 엔티티에 매우 중복 된 몇 가지 방법이 있다는 것을 깨달았습니다. 예를 들어, ID 필드 : 그들은 모두 공통의 [ID, DATECREATED, DATEUPDATED] 3 개 필드가 있도록

User findById(int id); 
Calendar findById(int id); 

내 테이블을 디자인했다. 이러한 필드는 일반적이므로 각 엔티티에 대해 이러한 메서드를 다시 작성하는 대신 공통된 동작을 원했습니다.

그래서 난 내 저장소 클래스 (UserRepository, CalendarRepository) 상속처럼 정의되어 공통의 "저장소"클래스를 만든 :

public class Repository<T> : IDisposable, IRepository<T> where T : class 
{ 
    protected MyContext context; 

    private DbLinq.Data.Linq.Table<T> currentTable; 

    protected Repository() { 
     context = new MyContext(); 

     Type currentType = this.GetType().GetGenericArguments()[0]; 
     currentTable = //Set currentTable based on currentType. e.g.: currentTable = context.User; 
    }   

    #region IRepository<T> Members 

    public T findById(int? id) 
    { 
     return currentTable.SingleOrDefault(d => d.ID == id); 
    } 

    public T findByDateCreated(DateTime dateCreated) 
    { 
     return currentTable.SingleOrDefault(d => DateTime.Equals(dateCreated, d.DateCreated)); 
    } 

    public T findByDateUpdated(DateTime dateUpdated) 
    { 
     return currentTable.SingleOrDefault(d => DateTime.Equals(dateUpdated, d.DateUpdated)); 
    } 

    public T insert(T domainObject) 
    { 
     currentTable.InsertOnSubmit(domainObject); 
     return domainObject; 
    } 

    public T save(T domainObject) 
    { 
     context.SubmitChanges(); 
     return domainObject; 
    } 

    #endregion 

    #region IDisposable Members 

    public void Dispose() 
    { 
     if (context != null) 
      context.Dispose(); 
    } 

    #endregion 
} 

잘 그것은이 내가 생각했던 것보다 더 어렵 밝혀졌습니다. 내가 설정하려고 할 때 :

currentTable = (Table<T>)context.User; 

나는 다음과 같은 오류가 발생합니다 :

Cannot convert type 'DbLinq.Data.Linq.Table<Models.Domain.User>' to 'DbLinq.Data.Linq.Table<T>' 

암시 적 캐스팅 중 하나가 작동하지 않습니다.

누구나 비슷한 결과를 얻었습니까? 모든 리포지토리 클래스가 정확히 동일한 코드로 동일한 findById 메서드를 구현해야한다면 매우 슬픈 일이 될 것입니다 ... 그렇게하지 않는 방법이있을 것이라고 확신합니다. 찾을 수 없습니다. . :)

+0

컴파일시 또는 런타임시 오류가 있습니까? – eglasius

답변

4

That'd be very sad if I had to have all my Repository classes implement the same findById method with exactly the same code in it

코드가 완전히 동일하지 않습니다. 각각의 경우에, 당신은 귀하의 맥락에서 다른 테이블을 참조하고 있습니다.

나는 귀하의 논리를 이해합니다. 너 DRY되고 싶다. 하지만 저장소가있는 이유는 실제 저장소 대신 모의 저장소를 주입하여 데이터 액세스 논리를 추상화하는 기능을 제공하여 단위 테스트를 용이하게하기 위해서입니다. 이 작업을 수행하는 가장 실용적인 (유연한) 방법은 테이블 (및 DAL 개체)을 분리하여 구분하는 것입니다. DAL 개체의 일부를 일반화하려고 시도하면 유닛 테스트를 복잡하게하는 추가 커플 링이 도입됩니다.

+0

True 참조 된 개체가 다르지만 코드가 동일합니다. 하지만 Unit testing 관점을 얻었습니다 ... IOC는 실제로 Ninject를 사용하여 다음 단계 중 하나였습니다. 도와 줘서 고마워. 로버트. – Lancelot

+0

@Robert는 똑같은 방법으로 5 개의 테이블을 가지고 있더라도 여전히 중요한 테스트입니다. DRYness에 대한 단위 테스트를 희생하고 싶다면 어떻게해야합니까? 3 일 전에 Lancelot과 동일한 문제로 고생했지만 여전히 모든 Log 테이블을 수용 할 수있는 일반 구조를 만들 수 없습니다. – AdrianoRR

+0

@AdrianoRR : 명확하게하기 위해 저장소의 목적은 데이터 지속성을 추상화하는 것입니다. 이는 단위 테스트를 용이하게하거나 기본 데이터 저장소를 다른 공급 업체로 대체 할 수 있도록하기 위해 수행 될 수 있습니다.실제로 단위 테스트는 저장소 메서드가 올바른 레코드를 반환하는지 확인하는 역할을하며 데이터 저장소를 거의 교환하지 않습니다. –

관련 문제