MVC DDD: Можно ли использовать репозитории вместе со службами в контроллере? - PullRequest
9 голосов
/ 26 августа 2010

большую часть времени в сервисном коде у меня будет что-то вроде этого:

public SomeService : ISomeService
{
    ISomeRepository someRepository;
    public Do(int id)
    {
        someRepository.Do(id);
    }
}

так что это немного избыточно

поэтому я начал использовать репозитории прямо в контроллере

это нормально? Есть ли какая-то архитектура, которая делает так?

Ответы [ 5 ]

5 голосов
/ 27 августа 2010

Вы теряете способность иметь бизнес-логику между ними.

Я не согласен с этим.

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

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


Я видел, как несколько человек упоминали об использовании связующих моделей для вызова в репонедавно.Откуда взялась эта безумная идея?

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

Мой связыватель моделей - это класс, который реализует IModelBinder , который принимает репозиторий в конструкторе (который внедряется и, следовательно, - может быть расширен, если нам нужно кэширование с некоторым базовым составом) и используетперед вызовом действия для извлечения совокупного корня и замены аргумента действия int id или Guid id или string slug или whatever реальным объектом домена.Объединяя это с аргументом модели представления ввода, мы можем писать меньше кода.Примерно так:

public ActionResult ChangeCustomerAddress
 (Customer c, ChangeCustomerAddressInput inp){
  c.ChangeCustomerAddress(inp.NewAddress);
  return RedirectToAction("Details", new{inp.Id});
}

В моем реальном коде это немного сложнее, поскольку включает проверку ModelState и некоторую обработку исключений, которые могут быть выброшены изнутри модели домена (извлечены в метод расширения Controller для повторного использования).Но не намного.Пока что самое длинное действие контроллера составляет ~ 10 строк.

Вы можете увидеть работающую реализацию (довольно сложную и (для меня) ненужную сложность) здесь .

Вы просто делаете CRUD-приложения с Linq To Sql или пробуете что-то с реальной доменной логикой?

Как вы можете (надеюсь) увидеть, такой подход фактически заставляет нас двигаться к * основанное на задачах приложение вместо CRUD-приложения.

Делая весь доступ к данным на уровне сервисов и используя IOC, вы можете получить множество преимуществ AOP, таких как невидимое кэширование, управление транзакциями и простотасостав компонентов, которые я не могу себе представить, вы получите с помощью связывателей моделей.

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

Пожалуйста, просветите меня.

Я не уверен, что сделал.Я не думаю, что я сам просветленный.:)


Здесь - базовый класс моей связующей модели. Вот одно из действий контроллера из моего текущего проекта.И вот «недостаток» бизнес-логики.

2 голосов
/ 26 августа 2010

Если вы используете репозитории в своих контроллерах, вы идете прямо с уровня данных на уровень представления.Вы теряете возможность иметь бизнес-логику между ними.

Теперь, если вы скажете, что будете использовать Сервисы только тогда, когда вам нужна бизнес-логика, и использовать репозитории повсюду, ваш код станет кошмаром.Уровень представления теперь вызывает и уровень бизнеса, и уровень данных, и у вас нет хорошего разделения проблем.

Я бы всегда пошел по этому пути: Repositories -> Services -> UI.Как только вы не думаете, что вам нужен бизнес-уровень, требования меняются, и вам придется переписывать ВСЕ.

1 голос
/ 19 декабря 2016

Вот эта вещь.

«Бизнес-логика» должна находиться в ваших сущностях и объектах стоимости.

Репозитории работают только с AggregateRoots.Таким образом, использование ваших репозиториев непосредственно в ваших контроллерах, похоже, вы воспринимаете это действие как «службу».Кроме того, поскольку ваш AggregateRoot может ссылаться на другие AR только по своему идентификатору, вам, возможно, придется позвонить более чем одному репо.Это действительно становится противным очень быстро.

Если вы собираетесь получать услуги, убедитесь, что вы предоставляете POCO, а не фактический AggregateRoot и его членов.

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

Ваш сервис ориентирован на API.Подумайте об этом ... если бы вы упаковали этот сервис в .dll для меня, чтобы использовать его, как бы вы создали свои методы таким образом, чтобы мне было легко узнать, что может сделать ваш сервис?Service.Update (объект) не имеет особого смысла.

И я даже не говорил о CQRS ... где все становится еще интереснее.

Ваш Web Api - просто КЛИЕНТ вашего Сервиса.Ваш сервис может быть использован другим сервисом, верно?Итак, подумай об этом.Скорее всего, вам понадобится Сервис для инкапсуляции операций в AggregateRoots, обычно путем их создания или извлечения из репозитория, что-то с этим делать, а затем возвращать результат.Обычно.

Имеет смысл?

0 голосов
/ 18 декабря 2016

Мои собственные грубые методы для DDD / MVC:

  • контроллеры зависят от приложения, поэтому они должны содержать только методы, специфичные для приложения, и вызывать методы Services.
  • все общедоступные методы Службы обычно являются атомарными транзакциями или запросами
  • только Службы создают экземпляры и хранят репозитории
  • мой домен определяет IContextFactory и IContext (массивная утечка, поскольку члены IContext являются IDBSet)
  • каждое приложение имеет своего рода корень композиции , который в основном создает экземпляр фабрики контекста для передачи в службы (вы можете использовать DI-контейнер, но это не сложно)

Это вынуждает меня держать свой бизнес-код и доступ к данным вне моих контроллеров.Я считаю, что это хорошая дисциплина, учитывая, насколько я свободен, когда не следую вышесказанному!

0 голосов
/ 09 сентября 2010

Даже при «богатой доменной модели» вам все равно потребуется доменная служба для обработки бизнес-логики, в которую вовлечены несколько объектов.Я также никогда не видел CRUD без некоторой бизнес-логики, но в простом примере кода.Я всегда хотел бы пойти по пути Мартина, чтобы сохранить мой код простым.

...