EF实体与服务模型与视图模型(MVC)

Jer*_*ose 24 asp.net-mvc entity-framework viewmodel

我正在尝试理解和设计您的应用程序/域模型(POCO/DTO)的良好实践.

假设我有以下数据库表,帐户:

UserID int
Email varchar(50)
PasswordHash varchar(250)
PasswordSalt varchar(250)
Run Code Online (Sandbox Code Playgroud)

当然,EF4会像这样构建实体:

public class Account
{
    public int UserID { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; }
    public string PasswordSalt { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

现在,假设我有一个用于注册新用户的视图模型,可能看起来像这样:

public class RegistrationViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

最后,我有一个需要注册用户的服务:

public class RegistrationService
{
    public void RegisterUser(??? registration)
    {
        // Do stuff to register user
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在试图弄清楚要传递给RegisterUser方法的内容.当然,视图模型位于我的Web应用程序(表示层)下,因此我不希望将其传递给我的服务.

所以,我在考虑以下四种可能性之一:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

3)传入Account实体,在我的控制器中执行RegistrationViewModel-to-Account映射:

public class RegistrationService
{
    public void RegisterUser(Account account)
    {
        // Do stuff to register user
    }
}
Run Code Online (Sandbox Code Playgroud)

4)将我的视图模型从演示文稿移到域/服务层,并将其传递给服务方法:

public class RegistrationService
{
    public void RegisterUser(RegistrationViewModel account)
    {
        // Do stuff to register user
    }
}
Run Code Online (Sandbox Code Playgroud)

这三种情况都不是理想的,因为我看到每种情况都存在问题.所以我想知道是否有另一种我无法想到的方法.

这有什么好的做法?

提前致谢.

Vas*_*y R 9

确定使用第3个选项.正如šljaker所说,服务应该不知道应用程序的呈现部分(您的ViewModel是其中的一部分).

当然,也不要过多地复制周围的事情,包括大量的过渡模型,RegistrationServiceModel或者 - 甚至更糟 - IRegistrationModel(最后一个会导致"接口爆炸"一天).

所以:

  1. 拥有一个Domain实体(POCO实体与Entity Framework或NHibernate或NoRM或其他任何东西一起持久化).
  2. 拥有一个ViewModel,它在给定的上下文中表示您的域模型.ViewModel如有必要,请毫不犹豫地进行每个控制器操作.严格的ViewModel(与您的View一致1:1)的副作用优点是完全没有过度发布和欠发布问题.这取决于你的具体情况/品味.
  3. 将DataAnnotation属性与ViewModel一起使用以提供基本验证(记住也要验证业务规则,但它应该位于电线后面 - 服务/存储库层内).
  4. 不要让App Service了解ViewModels.创建域实体实例并将其提供给服务(以验证/持久化).
  5. 使用AutoMapper作为选项,可以快速将域实体映射到ViewModel.
  6. 在Controller操作或自定义中从传入ViewModelFormCollection实体映射IModelBinder.
  7. (可选)我建议遵循Thunderdome原则.这是一个非常实在的ViewModels的方便使用.


šlj*_*ker 8

您永远不会将视图模型传递给服务.服务甚至不知道您可能已在表示层中定义的视图模型的存在.服务适用于域模型.
使用自动映射器在视图模型和域模型之间进行映射,反之亦然.

就个人而言,我从未听说过DDD服务模型(查看服务模型).