답변:
리포지토리 레이어는 데이터 액세스에 대한 추가적인 추상화 수준을 제공합니다. 쓰는 대신
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
데이터베이스에서 단일 항목을 가져 오려면 저장소 인터페이스를 사용하십시오.
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
전화하십시오 Get(id)
. 리포지토리 레이어는 기본 CRUD를 노출합니다 작업을 합니다.
서비스 계층은 리포지토리를 사용하는 비즈니스 로직을 노출합니다. 서비스 예는 다음과 같습니다.
public interface IUserService
{
User GetByUserName(string userName);
string GetUserNameByEmail(string email);
bool EditBasicUserData(User user);
User GetUserByID(int id);
bool DeleteUser(int id);
IQueryable<User> ListUsers();
bool ChangePassword(string userName, string newPassword);
bool SendPasswordReminder(string userName);
bool RegisterNewUser(RegisterNewUserModel model);
}
List()
저장소의 메소드는 모든 사용자를 리턴 하지만 ListUsers()
IUserService의 사용자는 하나만 리턴 할 수 있으며 사용자는 액세스 할 수 있습니다.
ASP.NET MVC + EF + SQL SERVER에는 다음과 같은 통신 흐름이 있습니다.
보기 <-컨트롤러-> 서비스 계층-> 리포지토리 계층-> EF-> SQL Server
서비스 계층-> 리포지토리 계층-> EF 이 부분은 모델에서 작동합니다.
뷰 <-컨트롤러-> 서비스 계층 이 부분은 뷰 모델에서 작동합니다.
편집하다:
/ Orders / ByClient / 5의 흐름 예 (특정 클라이언트의 순서를보고 싶습니다) :
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService; // injected by IOC container
}
public ActionResult ByClient(int id)
{
var model = _orderService.GetByClient(id);
return View(model);
}
}
주문 서비스를위한 인터페이스입니다.
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
이 인터페이스는 뷰 모델을 반환합니다.
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
인터페이스 구현입니다. 모델 클래스와 저장소를 사용하여 뷰 모델을 작성합니다.
public class OrderService : IOrderService
{
IRepository<Client> _clientRepository;
public OrderService(IRepository<Client> clientRepository)
{
_clientRepository = clientRepository; //injected
}
public OrdersByClientViewModel GetByClient(int id)
{
return _clientRepository.Get(id).Select(c =>
new OrdersByClientViewModel
{
Cient = new ClientViewModel { ...init with values from c...}
Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}
}
);
}
}
IRepository<>
에 GenericRepository<>
당신의 IOC 라이브러리에. 이 답변은 매우 오래되었습니다. 가장 좋은 해결책은 모든 리포지토리를 하나의 클래스로 결합하는 것 UnitOfWork
입니다. 모든 유형의 저장소와라는 하나의 메소드를 포함해야합니다 SaveChanges
. 모든 리포지토리는 하나의 EF 컨텍스트를 공유해야합니다.
Carnotaurus는 저장소가 데이터를 스토리지 형식에서 비즈니스 오브젝트로 맵핑 할 책임이 있다고 말했다. 스토리지에서 데이터를 읽고 쓰는 방법 (삭제, 업데이트도 모두)을 처리해야합니다.
반면에 서비스 계층의 목적은 비즈니스 재사용을 단일 장소로 캡슐화하여 코드 재사용 및 문제 분리를 촉진하는 것입니다. Asp.net MVC 사이트를 구축 할 때 이것이 실제로 실제로 의미하는 것은이 구조를 가지고 있다는 것입니다
[제어기]는 [서비스]를 호출합니다.
내가 찾은 유용한 한 가지 원칙은 컨트롤러 및 리포지토리에서 로직을 최소로 유지하는 것입니다.
컨트롤러에서는 DRY를 유지하는 데 도움이되기 때문입니다. 다른 곳에서 동일한 필터링 또는 논리를 사용해야하는 것이 매우 일반적이며 컨트롤러에 배치하면 재사용 할 수 없습니다.
리포지토리에서 더 나은 것이 나올 때 스토리지 (또는 ORM)를 교체 할 수 있기를 원하기 때문입니다. 그리고 저장소에 논리가 있으면 저장소를 변경할 때이 논리를 다시 작성해야합니다. 내 저장소가 IQueryable 만 반환하고 서비스가 필터링을 수행하는 경우 매핑 만 교체하면됩니다.
예를 들어 최근 몇 개의 Linq-To-Sql 리포지토리를 EF4로 교체했으며이 원칙을 지키지 않은 분은 몇 분 안에 교체 할 수있었습니다. 내가 몇 가지 논리를 가지고있는 곳은 대신 몇 시간의 문제였습니다.
onBeforeBuildBrowseQuery
하고 쿼리 작성기를 사용하여 쿼리를 변경할 수 있는 위치를 생각 하고 있습니다.
받아 들여진 대답 (그리고 수백 번의 찬성)에는 큰 결함이 있습니다. 나는 이것을 주석에서 지적하고 싶었지만 30 개의 주석으로 거기에 묻힐 것입니다.
그런 식으로 구축 된 엔터프라이즈 응용 프로그램을 인수했으며 초기 반응은 WTH 입니까? 서비스 계층의 ViewModel? 수년간의 개발로 인해 협약을 변경하고 싶지 않았으므로 ViewModels를 계속 반환했습니다. 우리가 WPF를 사용하기 시작했을 때 그것은 악몽으로 변했습니다. 우리 (개발팀)는 항상 말하고 있습니다 : 어떤 ViewModel? 실제 하나 (WPF를 위해 작성한 것) 또는 서비스 하나? 웹 응용 프로그램 용으로 작성되었으며 심지어 UI에서 편집을 비활성화하기 위해 IsReadOnly 플래그가 있었습니다 . 한 단어로 인한 주요 결함 및 주요 결함 : ViewModel !!
같은 실수를 저지르기 전에, 위의 이야기 외에도 몇 가지 이유가 있습니다.
서비스 계층에서 ViewModel을 반환하는 것은 엄청난 일이 아닙니다. 그것은 다음과 같습니다.
이러한 서비스를 사용하려면 MVVM을 사용하는 것이 좋으며 여기에 사용해야하는 ViewModel이 있습니다. 아야!
서비스는 UI 어딘가에 표시 될 것이라고 가정합니다. 웹 서비스 나 Windows 서비스와 같은 비 UI 응용 프로그램에서 사용하는 경우 어떻게됩니까?
그것은 심지어 실제 ViewModel이 아닙니다. 실제 ViewModel에는 관찰 성, 명령 등이 있습니다. 이름이 잘못된 POCO 일뿐입니다. (이름이 중요한 이유는 위의 내 이야기를 참조하십시오.)
소비 애플리케이션은 프리젠 테이션 레이어 (ViewModel이이 레이어에서 사용됨)이고 C #을 더 잘 이해합니다. 또 다른 아야!
제발 하지마!
일반적으로 리포지토리는 엔티티를 채우는 스캐 폴딩으로 사용됩니다. 서비스 계층은 나가서 요청을 소싱합니다. 서비스 계층 아래에 리포지토리를 배치 할 수 있습니다.