Разница между хранилищем и уровнем обслуживания? - PullRequest
177 голосов
/ 19 февраля 2011

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

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

Ответы [ 5 ]

306 голосов
/ 19 февраля 2011

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

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...}     
             }
         );
     }
}
37 голосов
/ 19 февраля 2011

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

Цель сервисного уровня, с другой стороны, состоит в том, чтобы объединить бизнес-логику в одном месте, чтобы способствовать повторному использованию кода и разделению проблем.Что на практике это обычно означает для меня при создании сайтов Asp.net MVC, так это то, что у меня есть такая структура

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

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

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

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

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

14 голосов
/ 15 мая 2018

Принятый ответ (и сотни раз проголосовавший) имеет большой недостаток.Я хотел бы указать на это в комментарии, но он просто будет похоронен там в 30 комментариях, так что указывать здесь.

Я принял корпоративное приложение, которое было построено таким образом, и моя первоначальная реакция была WTH ?ViewModels в слое обслуживания?Я не хотел менять соглашение, потому что в него ушли годы разработки, поэтому я продолжил возвращать ViewModels.Мальчик это превратился в кошмар, когда мы начали использовать WPF.Мы (команда разработчиков) всегда говорили: какой ViewModel?Реальный (тот, который мы написали для WPF) или сервисный?Они были написаны для веб-приложения и даже имели флаг IsReadOnly для отключения редактирования в пользовательском интерфейсе.Major, главный недостаток и все из-за одного слова: ViewModel !!

Прежде чем вы совершите ту же ошибку, вот еще несколько причин в дополнение к моей истории выше:

Возвращение ViewModel из сервисного слоя - это огромное нет, нет.Это все равно что сказать:

  1. Если вы хотите использовать эти сервисы, вам лучше использовать MVVM, а вот ViewModel, который вам нужно использовать. Ой!

  2. Сервисы предполагают, что они будут где-то отображаться в пользовательском интерфейсе. Что, если оно используется приложением, не являющимся пользовательским интерфейсом, таким как веб-службы или службы Windows?

  3. Это даже не настоящая модель представления. Настоящая ViewModel имеет наблюдаемость, команды и т. Д. Это просто POCO с дурным именем.(См. Мою историю выше, чтобы узнать, почему имена имеют значение.)

  4. Потребляющее приложение лучше быть слоем представления (ViewModels используется этим слоем) и лучше понимает C #. Еще ой!

Пожалуйста, не делайте этого!

7 голосов
/ 19 февраля 2011

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

2 голосов
/ 30 сентября 2018

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

...