Подтвердить что ты не робот

Использование моделей View-Models с шаблоном репозитория

Я использую архитектуру N-многоуровневого приложения с доменными именами с EF code first в моем недавнем проекте, я определил свои контракты Repository В слое Domain. Основной контракт, чтобы сделать другое Repositories менее подробным:

public interface IRepository<TEntity, in TKey> where TEntity : class
{
   TEntity GetById(TKey id);
   void Create(TEntity entity);
   void Update(TEntity entity);
   void Delete(TEntity entity);
}

И специализированный Repositories за каждый Aggregation root, например:

public interface IOrderRepository : IRepository<Order, int>
{
    IEnumerable<Order> FindAllOrders();
    IEnumerable<Order> Find(string text);
    //other methods that return Order aggregation root
}

Как вы видите, все эти методы зависят от Domain entities. Но в некоторых случаях приложению UI нужны некоторые данные, которые не являются Entity, данные могут быть сделаны из двух или более данных энтерита (View-Model s), в этих случаях я определяю View-Model в Application layer, поскольку они тесно зависят от потребностей Application's, а не от Domain.

Итак, я думаю, что у меня есть 2 способа показать данные как View-Models в UI:

  • Оставьте специализированный Repository только Entities и сопоставьте результаты метода Repositories с View-Models, когда я хочу показать пользователю (обычно Application layer).
  • Добавьте несколько методов к моей специализированной Repositories, которые возвращают их результаты как View-Models напрямую, и используют эти возвращаемые значения в Application layer, а затем UI (эти специализированные контракты Repositories, которые я называю их Readonly Repository Contract s, введите Application layer в отличие от другого контракта Repositories 'e, который помещается в Domain). enter image description here

Предположим, my UI нуждается в View-Model с 3 или 4 свойствами (от 3 или 4 большой Entities). Эти данные могут быть сгенерированы с простой проекцией, но в случае 1, поскольку мои методы не могли получить доступ к View-Models, я должен получить все поля из всех 3 или 4 таблиц, иногда с огромными объединениями, а затем сопоставьте результаты с View-Models. Но в случае 2 я мог просто использовать проекцию и непосредственно заполнить View-Model.

Итак, я думаю, что с точки зрения производительности случай 2 лучше, чем случай 1. но я читал, что Repository должен зависеть от Entities, а не View-Models в проектной точке.

Есть ли лучший способ, который не приводит к тому, что уровень Domain зависит от Application layer, а также не влияет на производительность? или допустимо, что для чтения запросов мой Repositories зависит от View-Models? (case2)

4b9b3361

Ответ 1

Возможно, использование разделения командной строки (на уровне приложения) может немного помочь.

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

Затем создайте отдельную прочитанную модель, которая может быть такой же грязной, как вы пожелаете, - добавьте туда 5 таблиц, код, который читает из файла число звезд во Вселенной, умножает его с количеством книг, начиная с A (после выполнения запроса против Amazon) и создает n-мерную структуру, которая и т.д. - вы получаете идею:) Но, на модели чтения, не добавляйте код, который имеет дело с изменяя ваши сущности. Вы можете возвращать любые модели просмотра, которые вы хотите, из этой модели чтения, но активируете любые изменения данных здесь.

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

С точки зрения производительности, используя прочитанную модель, то есть написание кода, который читает данные отдельно от кода, который пишет/изменяется, так как вы можете получить:) Это связано с тем, что вы даже можете калечить некоторый код SQL там, где не спал плохо ночью, - и SQL-запросы, если они хорошо написаны, значительно повысят скорость вашего приложения.

Nota bene: я немного шутил о том, что и как вы можете закодировать свою сторону чтения - код на стороне чтения должен быть как чистый и простой, как код на стороне записи, конечно: )

Кроме того, вы можете избавиться от общего интерфейса репозитория, если хотите, поскольку он просто загромождает домен, который вы моделируете, и заставляет каждый конкретный репозиторий выставлять методы, которые не нужны:) См. это. Например, весьма вероятно, что метод Delete() никогда не будет использоваться для OrderRepository - поскольку, возможно, Заказы никогда не должны удаляться (конечно, как всегда, это зависит). Конечно, вы можете поддерживать примитивы управления строкой базы данных в одном модуле и повторно использовать эти примитивы в своих конкретных хранилищах, но не подвергать эти примитивы кому-либо другому, кроме реализации репозиториев, просто потому, что они больше не нужны нигде и может запутать пьяного программиста, если его публично раскрыли.

Наконец, возможно, было бы неплохо не думать о слое уровня домена, слое приложений, слое данных или просмотре моделей слишком строгим образом. Пожалуйста, прочитайте это. Упаковка ваших программных модулей по их реальному значению/назначению (или функции) немного лучше, чем упаковка их на основе неестественный, трудно понятный, труднообъяснимый-к-5-old-kid критерий, то есть упаковка их по уровню.

Ответ 2

Хорошо, для меня я бы привязал объекты ViewModel к объектам модели и использовал их в своих репозиториях для чтения/записи, так как вы можете знать, что есть несколько инструментов, которые вы можете сделать для этого, в моем личном случае я использую automapper, который я нашел очень простым в реализации.

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

Опция может заключаться в том, что вы можете использовать DTO в службе и автоматизировать эти объекты на веб-уровне (возможно, это может быть случайное сопоставление), недостатком является то, что вы можете получить много шаблонов код и модели dtos и view могут быть дублированы.

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

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

Ответ 3

I Kindof согласен с Педро здесь. использование уровня сервиса приложения может быть benificial. если вы нацелились на реализацию типа MVVM, я бы посоветовал создать класс Model, который отвечает за хранение данных, которые извлекаются с использованием уровня сервиса. Сопоставление данных с automapper - это действительно хорошая идея, если ваши сущности, DTO и модели названы последовательно (так что вам не нужно писать много ручных сопоставлений).

В моем опыте использования ваших сущностей /poco в режимах просмотра для отображения данных вы получите большие шарики грязи. Различные представления имеют разные потребности, и все это добавит необходимость добавления дополнительных свойств для объекта. Медленно делая ваши запросы более сложными и медленными.

если ваши данные не изменяются, что часто вы можете рассмотреть возможность представления (sql/database), которые будут переносить некоторые тяжелые нагрузки в базу данных (там, где она сильно оптимизирована). EF достаточно хорошо обрабатывает представления базы данных. Затем получение объекта и отображение данных (из представлений) на модель или DTO становится довольно простым.