Модели EF и модели обслуживания против моделей (MVC)
Я пытаюсь понять и нарисовать примеры для разработки моделей приложений/доменов (POCOs/DTOs).
Скажем, у меня есть следующая таблица базы данных, Учетная запись:
UserID int
Email varchar(50)
PasswordHash varchar(250)
PasswordSalt varchar(250)
Конечно, EF4 построил бы сущность так:
public class Account
{
public int UserID { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
public string PasswordSalt { get; set; }
}
Теперь скажем, у меня есть модель просмотра для регистрации нового пользователя, которая может выглядеть примерно так:
public class RegistrationViewModel
{
public string Email { get; set; }
public string Password { get; set; }
}
Наконец, у меня есть служба, которая должна регистрировать пользователя:
public class RegistrationService
{
public void RegisterUser(??? registration)
{
// Do stuff to register user
}
}
Я пытаюсь понять, что нужно передать в метод RegisterUser. Разумеется, модель просмотра находится под моим веб-приложением (уровень представления), поэтому я не хочу, чтобы это передавалось моей службе.
Итак, я думаю о одной из четырех возможностей:
1) Настройте модель сервиса, которая аналогична, если не идентична, для параметра RegistrationViewModel и используйте это:
public class RegistrationServiceModel
{
public string Email { get; set; }
public string Password { get; set; }
}
public class RegistrationService
{
public void RegisterUser(RegistrationServiceModel registration)
{
// Do stuff to register user
}
}
2) Настройте интерфейс модели и наследуйте ее в моей модели представления и настройте мой метод для приема интерфейса:
public interface IRegistrationModel
{
string Email;
string Password;
}
public class RegistrationServiceModel : IRegistrationModel
{
public string Email { get; set; }
public string Password { get; set; }
}
public class RegistrationService
{
public void RegisterUser(IRegistrationModel registration)
{
// Do stuff to register user
}
}
3) Перейдите в объект Account, выполнив сопоставление RegistrationViewModel-to-Account в моем контроллере:
public class RegistrationService
{
public void RegisterUser(Account account)
{
// Do stuff to register user
}
}
4) Переместите мою модель представления из презентации в уровень домена/службы и передайте ее в метод службы:
public class RegistrationService
{
public void RegisterUser(RegistrationViewModel account)
{
// Do stuff to register user
}
}
Ни один из этих трех сценариев не кажется идеальным, поскольку я вижу проблемы в каждом из них. Поэтому мне интересно, есть ли другой способ, о котором я не могу думать.
Каковы хорошие практики для этого?
Спасибо заранее.
Ответы
Ответ 1
Вы никогда не передаете модель просмотра в службу. Служба даже не знает о существовании модели представления, которую вы могли бы определить в своем уровне представления. Служба работает с моделями доменов.
Используйте Auto mapper для сопоставления между моделью модели и моделью домена и наоборот.
Лично я никогда не слышал о моделях обслуживания в DDD (просматривать модели для служб).
Ответ 2
Используйте опцию 3rd, конечно. Как сказал šljaker, служба должна быть не осведомлена о части представления заявки (с которой ваша ViewModel является частью).
Несомненно, не переусердствуйте, включив в себя тонны переходных моделей, таких как RegistrationServiceModel
или - еще хуже - IRegistrationModel
(последний из них однажды приведет к "взрыву интерфейса" ).
Итак:
- Имейте объект домена (объект POCO, который сохраняется в Entity Framework или NHibernate или NoRM или что-то еще).
- Имейте ViewModel, который представляет вашу модель домена в данном контексте. Не стесняйтесь делать
ViewModel
за действие контроллера, если это необходимо. Преимущество побочных эффектов строгих ViewModels (те, которые составляют 1:1 с вашим представлением) - это полное отсутствие проблем с пересылкой и недопоставлением. Это зависит от конкретной ситуации/вкуса.
- Используйте атрибуты DataAnnotation с помощью ViewModels для обеспечения базовой проверки (не забудьте также проверить бизнес-правила, но он должен сидеть за проводом - внутри уровня "Службы/Хранилища" ).
- Не позволяйте службе App когда-либо знать о ViewModels. Создайте экземпляр сущности домена и подайте его в службу вместо (для проверки/сохранения).
- Используйте AutoMapper в качестве опции для быстрой карты из ваших объектов домена в ViewModels.
- Карта из входящих
ViewModel
или FormCollection
в вашу сущность либо в действии контроллера, либо в обычном IModelBinder
.
- (необязательно) Я бы рекомендовал следовать Принцип Thunderdome. Это действительно действительно удобное использование ViewModels.
Ответ 3
В этом случае имеет смысл использовать DTO (объект передачи данных). Вы можете создать класс AccountDto
на уровне сервиса и использовать его для передачи регистрационных данных в службу. В некоторых случаях он может быть похож на ViewModel, но обычно вы можете показать гораздо больше в своем представлении, чем требуется для создания пользователя. Чтобы проиллюстрировать это, ваш ViewModel, вероятно, по крайней мере будет выглядеть примерно так:
public class RegistrationViewModel
{
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
[Compare("Password")]
public string RepeatPassword { get; set; }
}
Пока ваш DTO будет требовать только свойства Email
и Password
.
public class AccountDto
{
public string Email { get; set; }
public string Password { get; set; }
}
Итак, как вы видите, ViewModel
содержит только данные, необходимые для View
. Логика проверки подлинности электронной почты и пароля выполняется на вашем веб-уровне. Вы используете DTO для получения только электронной почты и пароля для Сервиса. И затем на уровне сервиса вы получите пароль, заселите объект Entity и сохраните значения в базе данных.