저장소 패턴을 올바르게 사용하는 방법은 무엇입니까?
리포지토리를 어떻게 그룹화해야하는지 궁금합니다. asp.net mvc에서 본 예제와 마찬가지로 내 책에서는 기본적으로 데이터베이스 테이블 당 하나의 저장소를 사용합니다. 그러나 그것은 조롱과 물건을 위해 나중에 많은 저장소를 호출 해야하는 많은 저장소처럼 보입니다.
그래서 나는 그들을 그룹화해야한다고 생각합니다. 그러나 나는 그들을 그룹화하는 방법을 잘 모르겠습니다.
지금은 모든 등록 작업을 처리하기 위해 등록 저장소를 만들었습니다. 그러나 업데이트해야하는 4 개의 테이블이 있으며이를 수행하기 위해 3 개의 리포지토리가 있습니다.
예를 들어 테이블 중 하나는 라이센스 테이블입니다. 그들이 등록 할 때 나는 그들의 키를보고 데이터베이스에 존재하는지 확인합니다. 이제 등록이 아닌 다른 지점에서이 라이센스 키 또는 해당 테이블의 다른 것을 확인해야하는 경우 어떻게됩니까?
한 자리는 로그인 일 수 있습니다 (키가 만료되지 않았는지 확인).
그래서이 상황에서 무엇을할까요? 코드를 다시 작성 하시겠습니까 (DRY 중단)? 이 두 개의 저장소를 함께 병합하고 다른 시점에 메서드가 필요하지 않기를 바랍니다 (예 : userName이 사용되는지 확인하는 메서드가있을 수 있습니다. 다른 곳에서 필요할 수도 있습니다).
또한 그들을 병합하면 사이트의 두 가지 다른 부분에 대한 모든 논리가 길어지고 ValidateLogin (), ValdiateRegistrationForm ()과 같은 이름을 가져야한다고 생각하기 때문에 동일한 저장소로가는 2 개의 서비스 레이어가 필요합니다. , ValdiateLoginRetrievePassword () 등
아니면 리포지토리에 전화를 걸어 이상한 이름을 가지고 계십니까?
응용 프로그램의 여러 지점에서 사용할 수 있고 여전히 이해할 수 있도록 일반적인 이름을 가진 저장소를 만드는 것이 어려워 보이며 저장소에서 다른 저장소를 호출하는 것이 좋은 방법이라고 생각하지 않습니까?
리포지토리 패턴을 가지고 놀 때 내가 잘못한 한 가지는 당신처럼, 그 테이블이 리포지토리 1 : 1과 관련이 있다고 생각했습니다. 도메인 기반 설계의 일부 규칙을 적용하면 저장소 그룹화 문제가 종종 사라집니다.
리포지토리는 테이블이 아닌 집계 루트 당이어야 합니다. 즉, 엔티티가 혼자 살지 않아야하는 경우 (예 : Registrant
특정 참여 가있는 경우 Registration
)는 엔티티 일 뿐이며 저장소가 필요하지 않으며 집계 루트 저장소를 통해 업데이트 / 생성 / 검색해야합니다. 속한다.
물론-대부분의 경우 저장소 수를 줄이는이 기술 (실제로는 도메인 모델을 구조화하는 기술)은 적용 할 수 없습니다. 모든 엔티티가 집계 루트 여야하므로 (도메인에 크게 의존하며, 블라인드 추측 만 제공 할 수 있습니다.) 귀하의 예에서- 엔티티의 License
컨텍스트없이 확인할 수 있어야하기 때문에 집계 루트 인 것 같습니다 Registration
.
그러나 그것은 우리가 저장소를 계단식으로 만드는 것을 제한하지 않습니다 ( Registration
저장소는 License
필요한 경우 저장소 를 참조 할 수 있습니다). 그것은 우리가 객체 License
에서 직접 저장소 를 참조하도록 제한하지 않습니다 (바람직하게는 IoC를 통해) Registration
.
기술이 제공하는 복잡성이나 오해를 통해 디자인을 추진하지 마십시오. ServiceX
2 개의 저장소를 구성하고 싶지 않기 때문에 저장소를 그룹화하는 것은 좋은 생각이 아닙니다.
훨씬 더 나은에게 적절한 이름을 부여하는 것 - RegistrationService
즉,
그러나 서비스는 일반적으로 피해야합니다. 종종 빈혈 도메인 모델로 이어지는 원인이됩니다 .
편집 :
IoC 사용을 시작하십시오. 의존성 주입의 고통을 진정으로 덜어줍니다.
작성하는 대신 :
var registrationService = new RegistrationService(new RegistrationRepository(),
new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());
다음과 같이 작성할 수 있습니다.
var registrationService = IoC.Resolve<IRegistrationService>();
추신 소위 공통 서비스 로케이터 를 사용하는 것이 더 낫지 만 그것은 단지 예일뿐입니다.
이 문제를 해결하기 위해 시작한 한 가지는 실제로 N 개의 저장소를 래핑하는 서비스를 개발하는 것입니다. DI 또는 IoC 프레임 워크가이를 더 쉽게 만드는 데 도움이되기를 바랍니다.
public class ServiceImpl {
public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { }
}
말이 돼? 또한이 저택의 서비스에 대해 말하는 것이 실제로 DDD 원칙을 준수 할 수도 있고 그렇지 않을 수도 있음을 이해합니다. 작동하는 것처럼 보이기 때문에 그렇게합니다.
내가하는 일은 다음과 같이 정의 된 추상 기본 클래스가 있습니다.
public abstract class ReadOnlyRepository<T,V>
{
V Find(T lookupKey);
}
public abstract class InsertRepository<T>
{
void Add(T entityToSave);
}
public abstract class UpdateRepository<T,V>
{
V Update(T entityToUpdate);
}
public abstract class DeleteRepository<T>
{
void Delete(T entityToDelete);
}
그런 다음 추상 기본 클래스에서 리포지토리를 파생하고 예를 들어 일반 인수가 다른 경우 단일 리포지토리를 확장 할 수 있습니다.
public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>,
ReadOnlyRepository<string, IRegistrationItem>
기타....
일부 리포지토리에 제한이 있고 최대의 유연성을 제공하기 때문에 별도의 리포지토리가 필요합니다. 도움이 되었기를 바랍니다.
나는 이것을 내 저장소 클래스로 가지고 있고 예, 테이블 / 영역 저장소에서 확장하지만 여전히 때때로 DRY를 깨야합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MvcRepository
{
public class Repository<T> : IRepository<T> where T : class
{
protected System.Data.Linq.DataContext _dataContextFactory;
public IQueryable<T> All()
{
return GetTable.AsQueryable();
}
public IQueryable<T> FindAll(Func<T, bool> exp)
{
return GetTable.Where<T>(exp).AsQueryable();
}
public T Single(Func<T, bool> exp)
{
return GetTable.Single(exp);
}
public virtual void MarkForDeletion(T entity)
{
_dataContextFactory.GetTable<T>().DeleteOnSubmit(entity);
}
public virtual T CreateInstance()
{
T entity = Activator.CreateInstance<T>();
GetTable.InsertOnSubmit(entity);
return entity;
}
public void SaveAll()
{
_dataContextFactory.SubmitChanges();
}
public Repository(System.Data.Linq.DataContext dataContextFactory)
{
_dataContextFactory = dataContextFactory;
}
public System.Data.Linq.Table<T> GetTable
{
get { return _dataContextFactory.GetTable<T>(); }
}
}
}
편집하다
public class AdminRepository<T> : Repository<T> where T: class
{
static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString);
public AdminRepository()
: base( dc )
{
}
I also have a datacontext which was created using Linq2SQL.dbml class.
So now I have a standard repository implementing standard calls like All and Find and in my AdminRepository I have specific calls.
Doesn't answer the question of DRY though I don't think.
Here is an example of a generic Repository implementation using FluentNHibernate. It is capable of persisting any class that you have written a mapper for. It is even capable of generating your database based off of the mapper classes.
The Repository pattern is a bad design pattern. I work with many old .Net projects and this pattern typically causes "Distributed Transactions", "Partial Rollback" and "Connection Pool Exhausted" errors which could be avoided. The problem is that the pattern tries to handle connections and transactions internally but those should be handled at the Controller layer. Also EntityFramework already abstracts a lot of the logic. I would suggest using the Service pattern instead to reuse shared code.
I suggest you to look at Sharp Architecture. They suggest using one repository per entity. I'm using it currently in my project and wery pleased with results.
참고URL : https://stackoverflow.com/questions/1495553/how-to-use-the-repository-pattern-correctly
'Programing' 카테고리의 다른 글
pkg 파일의 압축을 풀고 압축하는 방법은 무엇입니까? (0) | 2020.09.16 |
---|---|
스프링 부트 @ResponseBody는 엔티티 ID를 직렬화하지 않습니다. (0) | 2020.09.16 |
부모 div를 채우기 위해 div 높이를 늘리는 방법-CSS (0) | 2020.09.15 |
직관 론적 유형 이론과 동등한 조합 논리는 무엇입니까? (0) | 2020.09.15 |
DELETE 요청 본문에 대한 RESTful 대안 (0) | 2020.09.15 |