Как работать с моделью представления с несколькими совокупными корнями? - PullRequest
5 голосов
/ 07 января 2010

На данный момент у меня довольно плохо модная модель.

Классы выглядят так =>

 public class AccountActionsForm
    {
        public Reader Reader { get; set; }
        //something...
    }

Проблема в том, что тип Reader основан на модели домена (нарушение SRP).

По сути, я ищу советы по проектированию (т. Е. Является ли хорошей идеей разделить модель представления на входы / выходы?), Как сделать мою модель представления менее удобной и удобной для разработчика (т.е. отображение должно работать автоматически с использованием контроллера базовый класс)?

Я знаю об инфраструктуре AutoMapper и, вероятно, собираюсь ее использовать.

Итак, еще раз - каковы распространенные ошибки при попытке создать правильную модель вида? Как это структурировать? Как выполняется сопоставление при необходимости ввода нескольких доменных объектов?


Меня смущают случаи, когда для просмотра требуются данные из более чем одного совокупного корня. Я создаю приложение, в котором есть такие объекты, как Library, Reader, BibliographicRecord и т. Д.

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

Итак, кажется, что можно создать вид OrderedBooksList с моделью вида OrderedBooksListModel, которая содержит модели вида LibraryOutput, ReaderOutput и BibliographicRecordOutput. Или еще лучше - OrderedBooksListModel просмотр модели, которая использует метод сплющивания и имеет реквизиты типа ReaderFirstName, LibraryName и т. Д.

Но это приводит к проблемам с отображением, поскольку существует более одного входа.
Это больше не соотношение 1: 1, где я бью только в один агрегированный корень. Означает ли это, что моя модель домена является неправильной?

А как быть с полями модели представления, которые находятся исключительно на уровне пользовательского интерфейса (т. Е. Enum, указывающий на отмеченную вкладку)?

Является ли этим , что каждый делает в таких случаях?

 FooBarViewData fbvd = new FooBarViewData();
   fbvd.Foo = new Foo(){ A = "aaa"};
   fbvd.Bar = new Bar(){ B = "bbb"};
   return View(fbvd);

Я не хочу этого делать =>

var fbvd = new FooBarViewData();
   fbvd.FooOutput =  _mapper.Map<Foo,FooOutput>(new Foo(){ A = "aaa"});
   fbvd.BarOutput = _mapper.Map<Bar,BarOutput>(new Bar(){ B = "bbb"});
   return View(fbvd);

Кажется, я много пишу. :)


Чтение этого в данный момент. И это .


Ok. Я много думал об этой проблеме, и да - добавление еще одного слоя абстракции кажется решением =>

alt text

Итак - по-моему, это уже работает, теперь пришло время немного поиграть.

ты Джимми

Ответы [ 3 ]

4 голосов
/ 11 января 2010

Трудно определить все это, но здесь идет. Нам нравится отделять то, что мы называем тем, что видит представление, от того, что строит контроллер. Вид видит сплющенный, мертвый мозг DTO-подобный объект. Мы называем это View Model.

На стороне контроллера мы строим богатый график того, что необходимо для построения модели представления. Это может быть только один агрегатный корень или композиция из нескольких агрегатных корней. Все это вместе объединяется в то, что мы называем моделью представления. Иногда Модель представления - это просто наша Модель Постоянства (Домена), но иногда это вообще новый объект. Однако на практике мы обнаружили, что если нам нужно построить составную модель представления, она становится магнитом для связанного поведения.

В вашем примере я бы создал ViewFooBarModel и ViewFooBarViewModel (или ViewFooBarModelDto). Затем я могу говорить о ViewFooBarModel в моем контроллере, а затем положиться на сопоставление, чтобы сгладить то, что мне нужно от этой промежуточной модели с AutoMapper.

4 голосов
/ 07 января 2010

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

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

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

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

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

Мы используем абстрактные средства отображения и службы для сопоставления PostModel с объектом домена, а затем, возможно, при необходимости возвращаемся к ViewModel.

3 голосов
/ 07 января 2010

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

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

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

...