Как работать с моделью представления с несколькими совокупными корнями?
На данный момент у меня довольно плохо выглядит модельная модель.
Классы выглядит так =>
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, где я пинаю только один сводный корень.
Означает ли это, что моя модель предметной области является неправильной?
А как насчет полей модели представления, которые живут исключительно на уровне пользовательского интерфейса (т. Е. Перечисление, которое указывает на отмеченную вкладку)?
Это то, что все делают в таких случаях?
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);
Похоже, много писать.:)
Читая это в данный момент. И это.
Хорошо. Я много думал об этой проблеме, и да - добавление еще одного слоя абстракции кажется решением =>
http://i46.tinypic.com/fe14qp.jpg
Так что, на мой взгляд, это уже работает, теперь пришло время немного поиграть.
ты Джимми
3 ответа
Трудно определить все это, но здесь идет. Нам нравится отделять то, что мы называем тем, что видит представление, от того, что строит контроллер. Вид видит сплющенный, мертвый мозг DTO-подобный объект. Мы называем это View Model.
На стороне контроллера мы строим богатый график того, что необходимо для построения модели представления. Это может быть только один агрегатный корень или композиция из нескольких агрегатных корней. Все это вместе объединяется в то, что мы называем моделью представления. Иногда Модель представления - это просто наша Модель Постоянства (Домена), но иногда это совершенно новый объект. Однако на практике мы обнаружили, что если нам нужно создать составную модель представления, она становится магнитом для связанного поведения.
В вашем примере я бы создал ViewFooBarModel и ViewFooBarViewModel (или ViewFooBarModelDto). Затем я могу говорить о ViewFooBarModel в моем контроллере, а затем положиться на сопоставление, чтобы сгладить то, что мне нужно от этой промежуточной модели с AutoMapper.
Вот одна вещь, которая дошла до нас после того, как мы долго боролись с альтернативами: рендеринг данных отличается от получения данных.
Мы используем ViewModels для визуализации данных, но быстро выяснилось, что, когда дело доходит до получения данных посредством отправки форм и тому подобного, мы не могли реально приспособить наши ViewModels к концепции ModelBinding. Основная причина заключается в том, что возврат в браузер часто приводит к потере данных.
Например, хотя мы используем ViewModels, они основаны на данных из реальных доменных объектов, но могут не предоставлять все данные из доменного объекта. Это означает, что мы не сможем немедленно восстановить базовый объект домена по данным, опубликованным браузером.
Вместо этого нам нужно использовать мапперы и репозитории для получения полных доменных объектов из опубликованных данных.
Прежде чем мы осознали это, мы много пытались реализовать пользовательские ModelBinder, которые могли бы реконструировать полный доменный объект или ViewModel из опубликованных данных, но теперь у нас есть отдельные PostModel, которые моделируют, как мы получаем данные.
Мы используем абстрактные средства отображения и сервисы для отображения PostModel на объект Domain, а затем, возможно, обратно к ViewModel, если это необходимо.
Хотя может не иметь смысла группировать несвязанные сущности (или, скорее, их репозитории) в объект или службу домена, может иметь смысл сгруппировать их на уровне представления.
Точно так же, как мы создаем пользовательские ViewModel, которые представляют данные Домена способом, особенно подходящим для конкретного приложения, мы также используем пользовательские сервисы уровня представления, которые комбинируют вещи по мере необходимости. Эти сервисы гораздо более специальные, поскольку они существуют только для поддержки определенного представления.
Зачастую мы скрываем эту службу за интерфейсом, чтобы конкретная реализация могла свободно использовать любые несвязанные внедренные объекты Domain, необходимые для создания желаемого результата.