Где конвертировать бизнес-модель для просмотра модели?
В моем приложении ASP.NET MVC я использую шаблоны единиц работы и репозитория для доступа к данным.
Используя единицу рабочего класса и определенный внутри него репозиторий, я извлекаю связанный набор сущностей в моем контроллере. Обладая знаниями для начинающих, я могу придумать два способа извлечь бизнес-модель и преобразовать ее для просмотра модели.
- Репозиторий возвращает бизнес-модель контроллеру, эта модель сопоставлена с моделью просмотра, или
- Сам репозиторий преобразует бизнес-модель для просмотра модели и затем возвращается в контроллер.
В настоящее время я использую первый подход, но мой код контроллера стал уродливым и длинным для моделей с множеством свойств.
С другой стороны, я думаю, поскольку мой репозиторий называется UserRepository (например), он должен возвращать бизнес-модель напрямую, а не какую-то модель, которая полезна только для одного представления.
Какой из них вы считаете лучшей практикой для больших проектов? Есть ли альтернативный способ?
Ответы
Ответ 1
Репозитории должны возвращать модели домена, а не просматривать модели. Что касается сопоставления между моделями и моделями представлений, я лично использую AutoMapper, поэтому у меня есть отдельный слой отображения, но этот слой вызывается из контроллера.
Вот как выглядит типичное действие контроллера GET:
public ActionResult Foo(int id)
{
// the controller queries the repository to retrieve a domain model
Bar domainModel = Repository.Get(id);
// The controller converts the domain model to a view model
// In this example I use AutoMapper, so the controller actually delegates
// this mapping to AutoMapper but if you don't have a separate mapping layer
// you could do the mapping here as well.
BarViewModel viewModel = Mapper.Map<Bar, BarViewModel>(domainModel);
// The controller passes a view model to the view
return View(viewModel);
}
который, конечно, может быть сокращен с помощью специального фильтра действий, чтобы избежать повторной логики отображения:
[AutoMap(typeof(Bar), typeof(BarViewModel))]
public ActionResult Foo(int id)
{
Bar domainModel = Repository.Get(id);
return View(domainModel);
}
Фильтр настраиваемых действий AutoMap подписывается на событие OnActionExecuted, перехватывает модель, переданную в результат просмотра, вызывает слой отображения (AutoMapper в моем случае), чтобы преобразовать его в модель представления и заменить его для представления. Представление, конечно же, строго типизировано для модели представления.
Ответ 2
Я думаю, что ваш репозиторий должен вернуть бизнес-модель.
Затем вы можете использовать инструмент, например Automapper, чтобы автоматически сопоставлять свойства с вашей моделью просмотра и может избавиться от ручной код сопоставления. Этот подход очень полезен, если вы не хотите раскрывать все свойства бизнес-объекта или компилируете структуру для представления.
Вы также можете найти эту статью, где вы можете избавиться от ручных картографических вызовов (вроде), а также обеспечить хорошую например, как использовать viewmodels и т.д. (на мой взгляд) - или получить хотя бы какое-то вдохновение.
Отрывок из сообщения (атрибут делает преобразование в виде загрузочной модели для viewmodel):
[AutoMap(typeof(Product), typeof(ShowProduct))]
public ActionResult Details(int id)
{
var product = _productRepository.GetById(id);
return View(product);
}
Ответ 3
Как уже упоминалось в других ответах, AutoMapper является хорошим решением.
Однако вы также можете написать методы расширения для преобразования вашей сущности во ViewModel и наоборот. Может быть, это лучше для небольших проектов с меньшим количеством классов Entity и Model.
Пример:
public static class Extension
{
public static MyViewModel ToModel(this MyEntity x)
{
return new MyViewModel
{
Id = x.Id,
Name = x.FirstName + " " + x.LastName,
UserId = x.User?.Id
};
}
}
И использовать:
// NOTE: "MyEntityTable" is of type "MyEntity"
List<MyViewModel> toReturn = _db.MyEntityTable
.Include(x => x.User) // Include other tables to join.
.Select(x => x.ToModel())
.ToList();