Является ли хорошей практикой использование EntityObjects в качестве модели (MVC)?

Я создаю свое первое веб-приложение MVC 4/Razor с помощью Entity Framework 5 и делаю небольшую домашнюю работу, прежде чем принимать какие-либо дизайнерские решения.

Я вижу, что объекты EF спускаются с EntityObject, который, как представляется, содержит много полезных материалов для лучшей практики, а не наименьшая из которых - оптимистичная обработка concurrency. Другими словами, если 2 человека загружают запись Джейн Доэ из 123 Maple Street одновременно, первая меняет свое имя на Джейн Смит, а вторая меняет свой адрес на 321 Maple Street, тогда очень легко разрешить объединение обоих изменений в запись без конфликтов, в то время как попытка второго пользователя изменить тот же самый поле, что и первый пользователь, приведет к ошибке.

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

Итак, я задаюсь вопросом о целесообразности использования DTO. Каковы причины использования DTO? Насколько плохо использовать EntityObject как или в модели MVC? Какое другое решение вы предложите включить оптимистическую обработку concurrency, как я уже говорил выше?

Ответ 1

Я вижу только плохие точки при передаче EntityObject непосредственно в представление:

  • Вам необходимо выполнить ручной ввод в белый список или черный список, чтобы предотвратить перенаправление и массовое присвоение
  • Становится очень легко случайным образом загружать дополнительные данные из вашего представления, что приводит к выбору проблем N + 1.
  • По моему личному мнению, модель должна тщательно собирать информацию, отображаемую в представлении, и в большинстве случаев (за исключением базового материала CRUD), представление содержит информацию из более чем одного EntityObject

Ответ 2

= Проводка комментария как ответ =

Объекты EF - это POCOs, так как пара версий назад (не уверена какая). Если вы хотите "EntityObject", вы должны использовать какой-то адаптер (я верю, что есть возможность облегчить миграцию приложений, но я бы не рекомендовал его использовать как часть нового проекта).

Если ваши классы моделей имеют связанные с EF методы, то да, это действительно так плохо. Но EF 5 не должен. Начиная с версии 4.1, я полагаю, они используют Proxies вместо того, чтобы расширять EntityObject именно по этой причине - чтобы использовать их в качестве моделей.

Просто посмотрите на свои .tt и сгенерированные файлы .cs. Это простые POCOs. Нет интерфейсов, нет базовых классов. Если вы получаете объект из структуры сущности и проверяете тип объекта, вы найдете что-то вроде System.Data.Entity.DynamicProxies.Employee_5E43C6C196[...]. Это класс, сгенерированный прокси-сервером. Однако, если вы делаете то же самое, но изменяете конфигурацию контекста базы данных до (dbContext.Configuration.ProxyCreationEnabled = false;), вы заработали себе хороший объект Employee!

Итак, чтобы ответить на исходный вопрос, совершенно приемлемо/хорошая практика использовать EF POCOs в качестве моделей, но убедитесь, что вы используете их как непостоянные объекты.

Дополнительная информация

Вам следует подумать о концепциях DDD и о внедрении DDD-устных paterns, таких как репозитории или что-нибудь, что вы чувствуете, используя comfertable.

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

Вы должны прочитать об AutoMapper, чтобы сделать вашу жизнь проще (хорошо сочетается с репозиториями или автономно). Это облегчит передачу из ProxyEmployee → Employee → ViewModel и наоборот.

Пример ужасного использования объектов EF:

return View(dbContext.employees.First());

Пример плохого # 1 использования объектов EF:

Employee e = dbContext.employees.First();
return View(new Employee { name = e.name, [...] });

Пример использования плохого # 2 использования объектов EF:

Employee e = dbContext.employees.First();
return View(new EmployeeViewModel{ employee = e });

Пример ok использования объектов EF:

Employee dbEmploye = dbContext.employees.First();
Employee e = new Employee { name = dbEmploye.name, [...] };
return View(new EmployeeViewModel { employee = e });

Пример хорошего использования объектов EF:

Employee e = dbContext.employees.First();
EmployeeViewModel evm = Mapper.Map<Employee, EmployeeViewModel>(e);
return View(evm);

Пример awesome использования объектов EF:

Employee e = employeRepository.GetFirstEmployee();
EmployeeViewModel evm = Mapper.Map<Employee, EmployeeViewModel>(e);
return View(evm);

Как Чак Норрис сделал бы это:

return View(EmployeeViewModel.Build(employeRepository.GetFirstEmployee()));

Ответ 3

On the other hand, it seems pretty standard practice to create lightweight Data Transfer Objects to pass data between the server and the client, and which serve as or in models for the MVC framework. This is great for ensuring minimal traffic to the client, but it screws up concurrency checking

Здесь вы, кажется, говорите о том, что перетекает через провод в браузер. В этом смысле, даже если вы используете классы EntityObject в своем контроллере, данные все равно должны быть переданы клиенту и отправлены обратно в более простой форме. Поэтому любая поддержка concurrency не актуальна, если вы находитесь на клиенте.

Ответ 4

Dtos имеет несколько преимуществ, но зависит от того, что вы планируете.

Если вы планируете их плоскую, то они лучше и проще для следующего:

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

Но если вам не нужно ничего из этого, вы можете просто обойтись.

Ответ 5

На основании того, что все ответы до сих пор показывают, что:

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

Я предложу свое собственное решение и приглашу ваши комментарии о том, думаете ли вы, что это хорошая идея.

Вместо того, чтобы передавать обычную ванильную DTO до клиента, мы создаем абстрактный класс GenericDTO<T>, где T представляет EntityObject. Мы также создаем класс GenericDTOProperty<T>, который имеет два свойства:

public class GenericDTOProperty<T> {
  public T LoadValue { get; internal set; }
  public T Value { get; set; }
}

Теперь скажем, что у меня есть EntityObject, называемый "Клиент", со свойствами для "ID" и "Name". Я бы создал класс DTO следующим образом:

public class CustomerDTO : GenericDTO<Customer> {
  public GenericDTOProperty<int> ID;
  public GenericDTOProperty<string> Name;
}

Не вдаваясь в слишком много спекулятивного кода здесь, я бы инкапсулировал код в класс GenericDTO, который использует отражение для копирования значений в и из EntityObject, устанавливая LoadValue при загрузке и проверяя, что он hasn ' t при сохранении. Вы можете получить еще умнее и поместить свойство ID в базовый класс, если вы уверены, что каждая таблица будет иметь одно поле ID.

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