각 개체에 대해 일반 리포지토리를 만드는 것과 특정 리포지토리를 만드는 것의 이점은 무엇입니까?
우리는 ASP를 개발하고 있습니다.NET MVC 응용 프로그램이며, 현재 리포지토리/서비스 클래스를 빌드하고 있습니다.모든 리포지토리가 고유한 인터페이스와 메서드 집합을 가지고 있는 것에 비해 모든 리포지토리가 구현하는 일반 IR 리포지토리 인터페이스를 만드는 데 큰 이점이 있는지 궁금합니다.
예를 들어, 일반 IR 저장소 인터페이스는 다음과 같습니다(이 답변에서 발췌).
public interface IRepository : IDisposable
{
T[] GetAll<T>();
T[] GetAll<T>(Expression<Func<T, bool>> filter);
T GetSingle<T>(Expression<Func<T, bool>> filter);
T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
void Delete<T>(T entity);
void Add<T>(T entity);
int SaveChanges();
DbTransaction BeginTransaction();
}
각 리포지토리는 다음과 같은 인터페이스를 구현합니다.
- 고객 저장소:IR 저장소
- 제품 저장소:IR 저장소
- 기타.
이전 프로젝트에서 수행한 대안은 다음과 같습니다.
public interface IInvoiceRepository : IDisposable
{
EntityCollection<InvoiceEntity> GetAllInvoices(int accountId);
EntityCollection<InvoiceEntity> GetAllInvoices(DateTime theDate);
InvoiceEntity GetSingleInvoice(int id, bool doFetchRelated);
InvoiceEntity GetSingleInvoice(DateTime invoiceDate, int accountId); //unique
InvoiceEntity CreateInvoice();
InvoiceLineEntity CreateInvoiceLine();
void SaveChanges(InvoiceEntity); //handles inserts or updates
void DeleteInvoice(InvoiceEntity);
void DeleteInvoiceLine(InvoiceLineEntity);
}
두 번째 경우, 표현식(LINQ 또는 그 외의 표현식)은 리포지토리 구현에 완전히 포함됩니다. 서비스를 구현하는 사용자는 어떤 리포지토리 기능을 호출할지만 알면 됩니다.
서비스 클래스에서 모든 표현 구문을 작성하고 저장소로 전달하는 것이 장점이라고 생각하지 않습니다.이것은 혼란이 쉬운 LINQ 코드가 많은 경우에 복제되고 있다는 것을 의미하지 않을까요?
예를 들어, 우리의 오래된 송장 처리 시스템에서, 우리는 다음과 같이 부릅니다.
InvoiceRepository.GetSingleInvoice(DateTime invoiceDate, int accountId)
몇 가지 서비스(고객, 송장, 계정 등)에서 제공됩니다.여러 곳에 다음을 쓰는 것보다 훨씬 깨끗해 보입니다.
rep.GetSingle(x => x.AccountId = someId && x.InvoiceDate = someDate.Date);
특정 접근 방식을 사용할 때의 유일한 단점은 Get* 함수의 많은 순열로 끝날 수 있다는 것입니다. 하지만 이는 식 논리를 서비스 클래스로 밀어 올리는 것보다 더 나은 것 같습니다.
제가 무엇을 빠뜨리고 있나요?
이것은 리포지토리 패턴 자체만큼이나 오래된 문제입니다. 최근 IQueryable
쿼리의 균일한 표현은 바로 이 주제에 대한 많은 토론을 야기했습니다.
저는 일반 저장소 프레임워크를 구축하기 위해 열심히 노력한 후 특정 저장소를 선호합니다.제가 어떤 교묘한 메커니즘을 시도했든 간에, 저는 항상 같은 문제에 봉착했습니다. 저장소는 모델링되는 도메인의 일부이며, 해당 도메인은 일반적이지 않습니다.모든 엔티티를 삭제할 수 있는 것은 아니며, 모든 엔티티를 추가할 수 있는 것도 아니며, 모든 엔티티에 리포지토리가 있는 것도 아닙니다.쿼리는 매우 다양합니다. 저장소 API는 엔티티만큼 고유해집니다.
제가 자주 사용하는 패턴은 특정 리포지토리 인터페이스를 사용하는 것이지만 구현을 위한 기본 클래스를 사용하는 것입니다.예를 들어 LINQ to SQL을 사용하여 다음 작업을 수행할 수 있습니다.
public abstract class Repository<TEntity>
{
private DataContext _dataContext;
protected Repository(DataContext dataContext)
{
_dataContext = dataContext;
}
protected IQueryable<TEntity> Query
{
get { return _dataContext.GetTable<TEntity>(); }
}
protected void InsertOnCommit(TEntity entity)
{
_dataContext.GetTable<TEntity>().InsertOnCommit(entity);
}
protected void DeleteOnCommit(TEntity entity)
{
_dataContext.GetTable<TEntity>().DeleteOnCommit(entity);
}
}
교체하다DataContext
당신이 선택한 작업 단위로.구현의 예는 다음과 같습니다.
public interface IUserRepository
{
User GetById(int id);
IQueryable<User> GetLockedOutUsers();
void Insert(User user);
}
public class UserRepository : Repository<User>, IUserRepository
{
public UserRepository(DataContext dataContext) : base(dataContext)
{}
public User GetById(int id)
{
return Query.Where(user => user.Id == id).SingleOrDefault();
}
public IQueryable<User> GetLockedOutUsers()
{
return Query.Where(user => user.IsLockedOut);
}
public void Insert(User user)
{
InsertOnCommit(user);
}
}
리포지토리의 공용 API는 사용자를 삭제할 수 없습니다.또한, 노출은IQueryable
완전히 다른 벌레 통조림입니다. 그 주제에 대한 의견은 배꼽만큼 많습니다.
저는 사실 브라이언의 게시물에 약간 동의하지 않습니다.저는 그가 옳다고 생각합니다. 궁극적으로 모든 것이 매우 독특하고 기타 등등입니다.그러나 동시에 대부분의 경우 설계 과정에서 생성됩니다. 모델을 개발하는 동안 일반 저장소를 설치하고 사용하면 앱을 매우 빠르게 설치한 다음 필요성을 발견하면 더 구체적으로 재설정할 수 있습니다.
따라서 이러한 경우에 저는 전체 CRUD 스택을 포함하는 일반 IR 저장소를 자주 만들었습니다. 그러면 API를 사용하여 사람들이 UI를 사용하고 통합 및 사용자 수용 테스트를 동시에 수행할 수 있습니다.그런 다음 레포 등에 대한 구체적인 쿼리가 필요하다는 것을 알게 되면 해당 종속성을 필요에 따라 특정 종속성으로 교체하고 거기서 시작합니다.하나의 근본적인 암시.생성 및 사용이 간편합니다(메모리 내 db, 정적 개체 또는 조롱된 개체 등에 연결할 수 있음).
그렇긴 하지만, 제가 최근에 시작한 일은 행동을 해체하는 것입니다.따라서 IDataFetcher, IDataUpdater, IDataInserter 및 IDataDeleter(예: IDataDeleter)에 대한 인터페이스를 사용하는 경우 인터페이스를 통해 요구사항을 혼합하여 정의한 다음 요구사항의 일부 또는 전부를 처리하는 구현을 사용할 수 있습니다. 애플리케이션을 구축하는 동안에도 do-it-all 구현을 주입할 수 있습니다.
폴.
재정의할 수 있는 메서드 서명이 있는 일반 리포지토리(또는 정확한 동작을 지정하는 일반 리포지토리 목록)에서 파생된 특정 리포지토리를 선호합니다.
특정 리포지토리로 포장된 일반 리포지토리가 있어야 합니다.이렇게 하면 공용 인터페이스를 제어할 수 있지만 일반 저장소에서 발생하는 코드 재사용의 이점을 얻을 수 있습니다.
공용 클래스 사용자 리포지토리: 리포지토리, IUserRepository
인터페이스가 노출되지 않도록 IUserRepository를 주입해야 하지 않나요?사람들이 말했듯이, 당신은 전체 CRUD 스택 등이 필요하지 않을 수도 있습니다.
언급URL : https://stackoverflow.com/questions/1230571/advantage-of-creating-a-generic-repository-vs-specific-repository-for-each-obje
'programing' 카테고리의 다른 글
이미 많은 수의 파일을 추적하고 있는 기존 리포지토리에 .gitignore 적용 (0) | 2023.05.01 |
---|---|
Excel에서 특정 워크시트를 활성화하는 방법은 무엇입니까? (0) | 2023.05.01 |
WPF에서 마진 속성을 애니메이션화하는 방법 (0) | 2023.05.01 |
C#에서 명령줄 인수를 구문 분석하는 가장 좋은 방법은 무엇입니까? (0) | 2023.05.01 |
Git에서 분기를 삭제하는 시기는 언제입니까? (0) | 2023.05.01 |