Разница между репозиторием и уровнем обслуживания?

В шаблонах проектирования ООП в чем разница между шаблоном репозитория и уровнем обслуживания?

Я работаю над приложением ASP.NET MVC 3, и я пытаюсь понять эти шаблоны проектирования, но мой мозг просто не получает его... еще.

Ответ 1

Уровень репозитория дает вам дополнительный уровень абстракции по доступу к данным. Вместо написания

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

Уровень сервиса → Уровень хранилища → EF. Эта часть работает с моделями.

Виды < - Контроллеры → Сервисный уровень Эта часть работает с моделями просмотра.

EDIT:

Пример потока для /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...}     
             }
         );
     }
}

Ответ 2

Как сказал Carnotaurus, репозиторий отвечает за сопоставление ваших данных из формата хранения с вашими бизнес-объектами. Он должен обрабатывать как чтение, так и запись данных (удаление, обновление) с и на хранилище.

С другой стороны, целью уровня обслуживания является инкапсуляция бизнес-логики в единое целое для содействия повторному использованию кода и разделению проблем. То, что это обычно означает для меня на практике при создании сайтов ASP.NET MVC, заключается в том, что у меня есть эта структура

[Контроллер] вызывает [Сервис (ы)], который вызывает [репозиторий (ы)]

Один из принципов, который я нашел полезным, заключается в том, чтобы свести логику к минимуму в контроллерах и репозиториях.

В контроллерах это потому, что помогает мне сушить. Очень распространено, что мне нужно использовать одну и ту же фильтрацию или логику где-то в другом месте, и если я поместил ее в контроллер, я не смогу ее повторно использовать.

В репозиториях это потому, что я хочу иметь возможность заменить мое хранилище (или ORM), когда что-то лучше приходит. И если у меня есть логика в репозитории, мне нужно переписать эту логику, когда я изменяю репозиторий. Если мой репозиторий возвращает только IQueryable, а служба выполняет фильтрацию, с другой стороны, мне нужно будет только заменить сопоставления.

Например, недавно я заменил несколько своих репозиториев Linq-To-Sql на EF4, и те, в которых я остался верны этому принципу, могли заменить его в считанные минуты. Там, где у меня была какая-то логика, это заняло несколько часов.

Ответ 3

Обычно репозиторий используется в качестве леса для заполнения ваших сущностей - уровень обслуживания будет выходить и запрашивать запрос. Вероятно, вы разместили бы репозиторий под своим уровнем обслуживания.