我在开发过程中遇到了一个有趣的问题。现在,我使用一个与数据库无关的工作层单元来抽象我的ASP MVC 4 Web应用程序中实际数据库依赖项的数据访问。
实现工作单元接口的每个单独的数据库项目都知道我的业务模型(直接进出数据库的模型)。我不太确定我对这种方法的看法,但这不是我要问的问题。
我是否应该使用像AutoMapper这样的解决方案将我的商业模式转换为域模型/从域模型转换 - 模型传递给视图并用于任何不应该访问数据库字段的工作(即ID) ?
例如,考虑我的BusinessModels项目,我有以下类
BusinessModels
/UserAccounts/
User.cs
- ID
- Username
- HashedPassword
- Salt
UserSettings.cs
- IsSubscribedToNewsletter
- AllowDirectEmails
使用AutoMapper将这些User和UserSettings模型绑定到单个模型中是否有意义
MyProject
/DomainModels/
User.cs
- Username
- HashedPassword
- Salt
- IsSubscribedToNewsletter
- AllowDirectEmails
出于观点的目的?
这个问题也延伸到非MVC项目,但我觉得当我正在研究一个MVC项目时,在该标签中询问它会更有意义。
TLDR在映射业务模型/实体以查看模型方面是否有任何意义,或者是否提供了不必要的抽象层?如果是这样,存储库是否包含业务模型或视图模型(它们会自动映射到引擎盖下的业务模型)?
答案 0 :(得分:1)
关于viewmodels我将它们视为您希望使用的数据的摘要。
因此,从您的示例中,您的viewmodel将包含来自User
和UserSettings
类的数据。假设您有一个名为UserData.cshtml
的视图,那么我会像这样编写代码:
public class UserDataViewModel
{
public string Username { get; set; }
public bool AllowDirectEmails { get; set; }
// etc ...
}
public ActionResult UserData()
{
var viewModel = new UserDataViewModel();
viewModel.UserName = "Whatever";
viewModel.AllowDirectEmails = false;
// Or however you get the data for the user.....
return View(viewModel)
}
希望你明白了。因此,您可以将来自外部类的信息合并到一个viewmodel类中。基本上在viewmodel类中将所有内容绑定在一起。
我将viewmodel类命名为与将要使用的视图相同的名称。这可以帮助编写文档,并使新手代码更容易使用。
答案 1 :(得分:1)
您可以将视图模型用于两个不同的事物:
(我知道,第二个是有争议的。但是使用视图模型并不奇怪)
GET操作的模型需要渲染视图所需的所有属性:
假设您有一个可以属于一个UserGroup的用户。
在这种情况下,如果要编辑用户,模型需要:
我会使用这样的模型:
public class EditUserModel
{
public User User {get;set;}
public SelectList UserGroups {get;set;}
}
如您所见,我直接将User添加为属性。但我不会将类别列表添加为属性,因为我不需要整个类别列表,并且视图中包含所有属性。此外,如果您对控制器进行单元测试,则可以验证SelectList是否符合预期(如果您在视图中创建了“用户组”列表,则无法完成)
但是,如果您不需要View中用户的所有属性,该怎么办?是否值得删除User属性,并为Name,Email,JoinedData,Active ...添加单独的属性?我认为anser是NO。想象一下,您添加/删除或重命名某些用户实体属性。如果在视图模型中有单独的属性,则在更新视图之前,您还必须更改它们。并且,如果您依赖自动映射(自动映射器,值注入器),您甚至不会意识到是否犯了一些错误。
我还说视图模型可用于将数据发布回控制器。所以你可以这样做:
[HttpPost]
public ActionResult Edit(EditUserModel userModel)
如果这样做,模型绑定器将使用表单控件中的值填充userModel。所以你会回到半空的模型。在这种情况下,UserGroups列表将为null,并且,根据您编辑的用户属性的数量,User也可以具有许多null / non-initialized属性。
为了避免出错,在某些情况下建议创建一个不同的模型(可能还有辅助类),以明确预计会发布到模型的内容。
例如,如果您有一个操作来显示整个用户数据,但只允许更改其密码,则可以创建一个具有两个属性的类:Password和PasswordConfirmation。
在这种情况下,POST的视图模型只能有Password和PasswordConfirmation。并为具有此继承属性的GET导出模型,以及用户组和用户列表。
为什么继承而不使用独立类?简单地说,当您使用Html.TextBoxFor(m => m.User.Name)
之类的东西时,只有当post动作的参数具有相同的结构时,Model Binder才能设置User属性的Name属性。即如果get的视图模型具有以下结构:
public ChangePasswordModel
{
public string Password {get;set;}
public string PasswordConfirmation {get;set;}
// extra properties, like the list of user groups, the user data...
}
帖子的模型有这样的结构:
public PostedChanegPasswordModel
{
public User User {get;set;}
}
Html.TextBoxFor(m => m.EditedUser.Name)
呈现的输入内容不会绑定到PostedEditViewModel的User.Name
。
但如果你这样做:
public EditUserModel : PostedEditUserModel
{
// extra properties, like the list of user groups
}
数据绑定没有任何问题。
通常,您必须小心使用用于发布和获取的模型。我建议使用尽可能多的不同视图模型。
何时使用自动属性映射到全新视图和不同模型?
您必须有充分的理由拥有不同的视图模型。这可能是从外部启动应用程序(即首先设计)的结果,或者是因为团队在实施业务逻辑之前或期间开发UI。
在这种情况下,您可以发现视图模型的类和视图本身已经定义,并且与您的实体非常相似,但不完全相同。当我认为使用映射器时,这是一个例子。
使用不同类的另一个原因是将接口与逻辑分离。但这通常只发生在前一种情况中。