Вид и модель домена, где выполнить расчет - PullRequest
1 голос
/ 03 апреля 2012

Я только начал использовать дизайн модели View & Domain в своем веб-приложении MVC, но у меня возник вопрос, где выполнять вычисления и другие действия, связанные с View.Ниже я попытаюсь привести пример.

Модель моего домена (Linq2Sql)

public class Product
{
  public int Id;
  public string Name;
}

Модель представления с новым свойством UserCount, которое я хотел бы рассчитать.

public class ProductViewModel
{
  public int Id;
  public string Name;
  public int UserCount;
}

Действие моего контроллера выглядит как

public ActionResult _SelectionClientSide_Products()
{
  IQueryable<Product> products = _repository.GetProducts(true); 
  var  model = Mapper.Map<IEnumerable<Product>, IEnumerable<ProductViewModel>>(products);                                
  return View(model);
}

Я запрашиваю данные с использованием метода репозитория и получаю IQueryable<Product> и отображаю его в списке ProductViewModel.Но мне также нужно выполнить еще одну операцию запроса, чтобы подсчитать количество пользователей для каждого запрашиваемого продукта и назначить все значения для ProductViewModel.Какой дизайн мне следует придерживаться, чтобы добиться этого?

Соотношение между таблицами

Products -> Orders - > Users

EDIT

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

    public ActionResult _SelectionClientSide_Products()
    {        
      Data = new ProductViewModelBuilder(_repository).Build();
      return View(Data);
    }

namespace PC.Models
{
            public class ProductViewModel
            {
                public int Id { get; set; }
                public string Name { get; set; }
                public int UsersCount { get; set; }
            }

            public class ProductViewModelBuilder
             {
                 private readonly IDataAccess _repository;

                 public ProductViewModelBuilder(IDataAccess repository)
                 {
                     _repository = repository;
                 }

                 public IQueryable<ProductViewModel> Build()
                 {
                     return _repository.GetProducts().Select(p=> new ProductViewModel
                                                                         {
                                                                             Id = p.Id, 
                                                                             Name = p.Name,
                                                                             UsersCount = _repository.CountUsers(p.Id)
                                                                         });         
                 }

            }
        }

1 Ответ

0 голосов
/ 03 апреля 2012

По моему мнению, к тому времени, когда ваш контроллер начнет настройку модели, больше не должно быть "логики" или разговоров с моделью. Наличие «строителя», который снова запрашивает модель, - плохая практика. Не совсем «ломая» схему MVC, но все же плохая практика. Ваша ViewModel зависит от вашего DAL. Плохой плохой мальчик. :)

Если вам нужно выполнить другой запрос, то это должно быть включено в исходный запрос. Вместо вызова _repository.GetProducts, вызовите другой метод, который не только получает продукты, но также получает счет. При необходимости создайте DTO.

Тогда ваш контроллер должен выглядеть так:

public ActionResult _SelectionClientSide_Products()
{
  var someDto = _repository.GetProductsAndUserCount(true); 
  var  model = Mapper.Map<IEnumerable<SomeDto>, IEnumerable<ProductViewModel>>(someDto);                                
  return View(model);
}

Лично я обращаюсь к общим репозиториям через специализированные, так как я не хочу IProductRepository интерфейса с 50 сигнатурами. Я выбираю расширения LINQ IEnumerable<T> («каналы и фильтры»), которые позволяют создавать сложные запросы и оставаться в моем домене.

Так что моя версия выше была бы:

public ActionResult _SelectionClientSide_Products()
{
  var someDto = _productRepository.Find().WithSomeCondition(true).ToSomeDto(); 
  var  model = Mapper.Map<IEnumerable<SomeDto>, IEnumerable<ProductViewModel>>(someDto);                                
  return View(model);
}

Кстати, почему вы говорите, что AutoMapper вызывает больше проблем, которые приносят пользу? AutoMapper сэкономил мне кучу повторяющегося кода. Если вы знаете, как правильно его использовать, это ваш лучший друг. Вручите самый важный пакет NuGet в моем текущем приложении.

...