서비스 대신 컨트롤러 호출 저장소를 사용하는 것은 나쁜 습관입니까?
더 설명하기 위해 :
좋은 디자인 컨트롤러에서는 서비스 및 서비스 사용 저장소를 호출한다는 것을 알았습니다.
그러나 때로는 컨트롤러에서 논리가 필요하지 않고 db에서 가져 와서보기 위해 전달해야합니다.
그리고 서비스를 호출 할 필요없이 저장소를 호출하면됩니다. 나쁜 습관입니까?
서비스 대신 컨트롤러 호출 저장소를 사용하는 것은 나쁜 습관입니까?
더 설명하기 위해 :
좋은 디자인 컨트롤러에서는 서비스 및 서비스 사용 저장소를 호출한다는 것을 알았습니다.
그러나 때로는 컨트롤러에서 논리가 필요하지 않고 db에서 가져 와서보기 위해 전달해야합니다.
그리고 서비스를 호출 할 필요없이 저장소를 호출하면됩니다. 나쁜 습관입니까?
답변:
아닙니다. 리포지토리 는 서비스이기도합니다.
저장소를 통해 검색 한 엔티티가 대부분의 비즈니스 로직을 처리하는 경우 다른 서비스가 필요하지 않습니다. 리포지토리 만 있으면 충분합니다.
엔티티를 조작하기 위해 통과해야하는 일부 서비스가 있더라도. 먼저 저장소에서 엔티티를 잡고 해당 서비스로 전달하십시오. 시도하기 전에 HTTP 404를 던질 수있는 것이 매우 편리합니다.
또한 읽기 시나리오의 경우 DTO / ViewModel에 프로젝트를 투영하기 위해 엔티티가 필요합니다. 그 사이에 서비스 계층이 있으면 종종 추악한 메소드를 많이 통과하게됩니다.
컨트롤러가 리포지토리를 직접 호출하는 것은 좋지 않습니다. "서비스"는 또 다른 도구이므로 의미가있는 곳에서 사용하십시오.
NikolaiDante는 다음과 같이 언급했습니다.
... 올바른 응용 분야에 적합한 패턴을 선택하십시오. 내가 말하고자하는 것은 응용 프로그램의 일관성을 유지해야한다는 것입니다.
일관성이 가장 중요한 측면이라고 생각하지 않습니다. "서비스"클래스는 컨트롤러가이를 구현할 필요가 없도록 상위 로직을 캡슐화하기위한 것입니다. 주어진 작업에 "높은 수준의 논리"가 필요하지 않으면 리포지토리로 직접 이동하십시오.
우려와 테스트 가능성을 분리 시키려면 리포지토리는 생성자를 통해 서비스에 주입하는 종속성이어야합니다.
IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);
service.DoSomething(...);
데이터베이스에서 레코드를 검색 할 때 일종의 매개 변수화 된 쿼리가 필요한 경우 서비스 클래스는 뷰 모델을 가져 와서 리포지토리에서 실행하는 쿼리를 작성하기에 좋은 장소 일 수 있습니다.
마찬가지로, 폼에 복잡한 뷰 모델이있는 경우 서비스 클래스는 도메인 모델 / 엔터티에서 메서드를 호출 한 다음 리포지토리를 사용하여 레코드를 유지하여 레코드를 생성, 업데이트 및 삭제하는 논리를 캡슐화 할 수 있습니다.
컨트롤러가 ID로 레코드를 가져와야하는 경우 반대 방향으로 가면 서비스 오브젝트에 위임하는 것은 슬레지 해머로 압정을 치는 것과 같습니다. 필요한 것 이상입니다.
컨트롤러가 트랜잭션 또는 작업 단위 오브젝트 를 처리하기에 가장 적합한 위치에 있음을 발견했습니다 . 그런 다음 컨트롤러 또는 작업 단위 (UOW) 오브젝트는 복잡한 조작을 위해 서비스 오브젝트에 위임하거나 간단한 조작을 위해 저장소로 직접 이동합니다 (예 : ID로 레코드 찾기).
public class ShoppingCartsController : Controller
{
[HttpPost]
public ActionResult Edit(int id, ShoppingCartForm model)
{
// Controller initiates a database session and transaction
using (IStoreContext store = new StoreContext())
{
// Controller goes directly to a repository to find a record by Id
ShoppingCart cart = store.ShoppingCarts.Find(id);
// Controller creates the service, and passes the repository and/or
// the current transaction
ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);
if (cart == null)
return HttpNotFound();
if (ModelState.IsValid)
{
// Controller delegates to a service object to manipulate the
// Domain Model (ShoppingCart)
service.UpdateShoppingCart(model, cart);
// Controller decides to commit changes
store.SaveChanges();
return RedirectToAction("Index", "Home");
}
else
{
return View(model);
}
}
}
}
나는 다양한 서비스와 리포지토리를 직접 사용하는 것이 완벽하게 허용된다고 생각합니다. 필요한 경우 트랜잭션을 작업 단위 (UOW) 오브젝트에 캡슐화 할 수 있습니다.
책임의 분류는 다음과 같습니다.
DbContext
이 경우 나쁜 이름 이라고 생각 합니다. 변경하겠습니다. NHibernate를 사용하고 리포지토리 (또는 편리한 경우 컨텍스트)는 데이터베이스 끝을 관리하므로 지속성 메커니즘 변경은 컨텍스트 외부의 코드 변경이 필요하지 않습니다.
아키텍처에 따라 다릅니다. 나는 Spring을 사용하며 트랜잭션은 항상 서비스에 의해 관리됩니다.
쓰기 작업 (리포지토리에 단순히 위임하는 논리가없는 간단한 서비스)을 위해 리포지토리를 직접 호출하는 경우 하나의 작업으로 수행해야하는 작업에 여러 데이터베이스 트랜잭션을 사용하고있을 수 있습니다. 그러면 데이터베이스에 일관성없는 데이터가 생성됩니다. 일반적으로 데이터베이스 작업은 작동하거나 실패해야하지만 절반 작업은 두통의 원인입니다.
따라서 컨트롤러에서 직접 리포지토리를 호출하거나 간단한 위임 서비스를 사용하는 것은 나쁜 습관이라고 생각합니다. 읽기 전용으로 시작하기 시작하면 곧 또는 한 명 또는 동료가 쓰기 작업을 수행하기 시작합니다.