什么是MVC中的ViewModel?

 2023-02-17    388  

问题描述

我是asp.net mvc的新手.我有一个问题,了解ViewModel的目的.

是什么是ViewModel,为什么我们需要一个用于ASP.NET MVC应用程序的ViewModel?

如果我有关于它的工作和解释的一个很好的例子,那将更好.

推荐答案

a

a view model表示您要在视图/页面上显示的数据,无论是用于静态文本还是可以添加到数据库中的静态文本或输​​入值(如文本框和下拉列表)(或编辑).它与你的

让我们说你有一个Employee class,它表示你的员工域模型,它包含以下属性(唯一标识符,名字,姓氏和日期创建):

public class Employee : IEntity
{
     public int Id { get; set; }

     public string FirstName { get; set; }

     public string LastName { get; set; }

     public DateTime DateCreated { get; set; }
}

视图模型与域模型不同,该模型仅包含要在视图上使用的数据(属性表示).例如,让我们说要添加新的员工记录,您的视图模型可能如下所示:

public class CreateEmployeeViewModel
{
     public string FirstName { get; set; }

     public string LastName { get; set; }
}

您可以看到它只包含两个属性.这两个属性也在员工域模型中.为什么你可能会问? Id可能无法从视图中设置,它可能由employee表生成.还可以在存储过程中或应用程序的服务层中设置DateCreated.所以在视图模型中不需要Id和DateCreated.当您查看员工的详细信息时,您可能希望显示这两个属性(已被捕获的员工)作为静态文本.

加载视图/页面时,员工控制器中的”创建操作”方法将创建此视图模型的实例,如果需要,填充任何字段,然后将此视图模型传递给”视图”/”页面”:

public class EmployeeController : Controller
{
     private readonly IEmployeeService employeeService;

     public EmployeeController(IEmployeeService employeeService)
     {
          this.employeeService = employeeService;
     }

     public ActionResult Create()
     {
          CreateEmployeeViewModel model = new CreateEmployeeViewModel();

          return View(model);
     }

     public ActionResult Create(CreateEmployeeViewModel model)
     {
          // Do what ever needs to be done before adding the employee to the database
     }
}

您的视图/页面可能如下所示(假设您使用ASP.NET MVC和Razor查看引擎):

@model MyProject.Web.ViewModels.CreateEmployeeViewModel

<table>
     <tr>
          <td><b>First Name:</b></td>
          <td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.FirstName)
          </td>
     </tr>
     <tr>
          <td><b>Last Name:</b></td>
          <td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
              @Html.ValidationMessageFor(m => m.LastName)
          </td>
     </tr>
</table>

因此,验证将仅在FirstName和LastName上完成.使用 fluentvalidation 您可能有这样的验证:

public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
{
     public CreateEmployeeViewModelValidator()
     {
          RuleFor(m => m.FirstName)
               .NotEmpty()
               .WithMessage("First name required")
               .Length(1, 50)
               .WithMessage("First name must not be greater than 50 characters");

          RuleFor(m => m.LastName)
               .NotEmpty()
               .WithMessage("Last name required")
               .Length(1, 50)
               .WithMessage("Last name must not be greater than 50 characters");
     }
}

和数据注释它可能看起来如此:

public class CreateEmployeeViewModel : ViewModelBase
{
    [Display(Name = "First Name")]
    [Required(ErrorMessage = "First name required")]
    public string FirstName { get; set; }

    [Display(Name = "Last Name")]
    [Required(ErrorMessage = "Last name required")]
    public string LastName { get; set; }
}

要记住的关键料理是视图型号仅代表您要使用的数据,否则.您可以想象所有不必要的代码和验证如果您有一个具有30个属性的域模型,并且只想更新单个值.鉴于此方案,您只在视图模型中只有一个值/属性,而不是域对象中的所有属性.

视图模型不仅可以包含一个数据库表的数据.它可以将数据与另一个表组合.拍摄我的例子关于添加新的员工记录.除了添加的第一个和姓氏,您可能还想添加员工部门.此部门列表将来自您的Departments表.所以现在您可以在一个视图模型中具有来自Employees和Departments表的数据.然后,您将需要在视图模型中添加以下两个属性并使用数据填充它:

public int DepartmentId { get; set; }

public IEnumerable<Department> Departments { get; set; }

在编辑员工数据(已添加到数据库中的员工)时,从上面的示例不会差异.创建视图模型,称为EditEmployeeViewModel.只有要在此视图模型中编辑的数据,如名字和姓氏.编辑数据并单击”提交”按钮.我不会太担心Id字段,因为Id值可能在URL中,例如:

http://www.yourwebsite.com/Employee/Edit/3

拍摄此Id并将其传递给存储库层,以及您的名字和姓氏值.

删除记录时,我通常按照与编辑视图模型相同的路径遵循相同的路径.我还有一个URL,例如:

http://www.yourwebsite.com/Employee/Delete/3

当查看第一次加载时,我会使用3.我将从数据库中获取员工的数据3.我会在我的视图/页面上显示静态文本,以便用户可以看到员工是什么被删除.当用户单击”删除”按钮时,我只需使用Id值3并将其传递给我的存储库图层.您只需要Id删除表中的记录.

另一个点,您真的需要每个动作的视图模型.如果是简单的数据,那么只需使用EmployeeViewModel即可.如果是复杂的视图/页面,它们彼此不同,那么我会建议您为每个用户使用单独的视图模型.

我希望这可以清除您对查看模型和域模型的任何混淆.

其他推荐答案

视图模型是表示特定视图中使用的数据模型的类.我们可以将此类用作登录页面的型号:

public class LoginPageVM
{
    [Required(ErrorMessage = "Are you really trying to login without entering username?")]
    [DisplayName("Username/e-mail")]
    public string UserName { get; set; }
    [Required(ErrorMessage = "Please enter password:)")]
    [DisplayName("Password")]
    public string Password { get; set; }
    [DisplayName("Stay logged in when browser is closed")]
    public bool RememberMe { get; set; }
}

使用此视图模型,您可以定义视图(剃刀视图引擎):

@model CamelTrap.Models.ViewModels.LoginPageVM

@using (Html.BeginForm()) {
    @Html.EditorFor(m => m);
    <input type="submit" value="Save" class="submit" />
}

和动作:

[HttpGet]
public ActionResult LoginPage()
{
    return View();
}

[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
    ...code to login user to application...
    return View(model);
}

生成此结果(在提交表单后拍摄的屏幕,验证消息):

您可以看到,视图模型具有许多角色:

  • 查看模型通过仅包含视图中表示的字段来记录视图.
  • 查看模型可能包含使用数据注释或idataErrorInfo的特定验证规则.
  • 视图模型定义了视图如何查找(对于LabelFor,EditorFor,DisplayFor evergers).
  • 视图模型可以组合不同数据库实体的值.
  • 您可以轻松地显示模板,以便查看模型,并在使用Display或editorfor everyers中重复使用它们.

视图模型的另一个例子及其检索:我们希望显示基本的用户数据,他的权限和用户名.我们创建一个特殊的视图模型,只包含必填字段.我们从数据库中检索来自不同实体的数据,但视图只意识到视图模型类:

public class UserVM {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool IsAdministrator { get; set; }
    public string MothersName { get; set; }
}

检索:

var user = db.userRepository.GetUser(id);

var model = new UserVM() {
   ID = user.ID,
   FirstName = user.FirstName,
   LastName = user.LastName,
   IsAdministrator = user.Proviledges.IsAdministrator,
   MothersName = user.Mother.FirstName + " " + user.Mother.LastName
}

其他推荐答案

编辑:我在我的博客上更新了这个答案:

我的答案有点冗长,但我认为将视图模型与其他类型的常用模型进行比较非常重要,以了解它们的不同以及为什么它们是必要的.

总结,并直接回答所要求的问题:

一般来说,视图模型是一个对象,其中包含呈现视图所需的所有属性和方法.查看模型属性通常与数据对象(如客户和订单)有关,另外,它们还包含与页面或应用程序本身相关的属性,例如用户名,应用程序名称等.查看模型提供了一个方便的对象来传递给渲染引擎创建HTML页面.使用视图模型的许多原因之一是查看模型提供了一种方法来测试某些演示任务,例如处理用户输入,验证数据,检索显示数据等.

这里是实体模型的比较(a.ka.dtos a.ka.模型),演示模型和视图模型.

数据传输对象a.k.a”model”

数据传输对象(DTO)是一个具有属性的类,它与数据库中的表架构匹配. DTO被命名为它们的常见用法,用于从数据存储和从数据存储中跳转数据.
DTOS的特征:

  • 是业务对象 – 他们的定义取决于应用程序数据.
  • 通常仅包含属性 – 没有代码.
  • 主要用于将数据传输到数据库.
  • 属性完全或紧密地匹配数据存储中的特定表格上的字段.

数据库表通常是归一化的,因此DTO通常也标准化.这使得它们用于呈现数据的限制.但是,对于某些简单的数据结构,它们通常会很好.

以下是DTO可能看起来的两个示例:

public class Customer
{
    public int ID { get; set; }
    public string CustomerName { get; set; }
}


public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; }
    public DateTime OrderDate { get; set; }
    public Decimal OrderAmount { get; set; }
}

演示模型

表示模型是一个实用程序类,用于在屏幕或报表上呈现数据.演示模型通常用于建模由来自多个DTO的数据组成的复杂数据结构.演示模型通常表示数据的非规范化视图.

演示模型的特性:

  • 是业务对象 – 他们的定义取决于应用程序数据.
  • 主要包含属性.代码通常限于格式化数据或将其转换为或从DTO转换为或从DTO转换.演示模型不应包含业务逻辑.
  • 通常存在一个非规范化的数据视图.也就是说,它们经常与多个DTO的性质组合.
  • 通常包含与DTO不同的基类型的属性.例如,美元金额可以表示为字符串,以便它们可以包含逗号和货币符号.
  • 通常由它们的使用方式以及它们的对象特征定义.换句话说,用作渲染网格的背衬模型的简单DTO实际上也是该网格上下文中的演示模型.

演示模型是”根据需要的”和”需要的”(而DTO通常与数据库模式相关).演示模型可用于为整个页面的数据,页面上的网格,或页面上的网格上的下拉列表.演示模型通常包含其他演示模型的属性.演示模型通常是为单一使用目的而构建的,例如在单个页面上渲染特定网格.

示例演示模型:

public class PresentationOrder
{
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
    public string CustomerName { get; set; }
    public Decimal OrderAmount { get; set; }
    public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}

查看模型

视图模型类似于呈现模型,其中是用于呈现视图的备份类.但是,它与演示模型或DTO有什么不同.视图模型通常包含与演示模型和DTO相同的属性,因此,它们通常为另一个而困惑.

视图模型的特征:

  • 是用于呈现页面或屏幕的单个数据源.通常,这意味着视图模型将公开每个属性,这些属性都需要正确呈现自己的任何控件.使View型号视图的单一数据源极大地提高了单元测试的能力和值.
  • 是 composite对象,包含包含应用程序数据的属性以及应用程序代码使用的属性.该特性在设计可重用性的视图模型时是至关重要的,并且在下面的示例中讨论.
  • 包含应用程序代码.查看模型通常包含在渲染期间调用的方法以及用户与页面交互时的调用.此代码通常涉及事件处理,动画,控制,样式等.
  • 包含代码调用业务服务的代码,以便检索数据或将其发送到数据库服务器.此代码通常被错误地放置在控制器中.从控制器调用业务服务通常限制了单元测试的视图模型的有用性.要清楚,查看模型本身不应包含业务逻辑,但应拨打对包含业务逻辑的服务.
  • 通常包含其他页面或屏幕的其他视图模型的属性.
  • 是写的”每页”或”每屏幕”.唯一的视图模型通常为应用程序中的每个页面或屏幕编写.
  • 通常从基类推导出来,因为大多数页面和屏幕共享公共属性.

查看模型组成

如前所述,查看模型是复合对象,因为它们在单个对象上组合应用程序属性和业务数据属性.视图模型中使用的常用应用程序属性的示例是:

  • 用于显示诸如错误消息,用户名,状态等的应用程序状态的属性.
  • 用于格式化,显示,风格化或动画控件的属性.
  • 用于数据绑定的属性,如列表对象和属性,该属性保存由用户输入的中间数据.

以下示例显示为什么查看模型的复合性质很重要,我们如何最好地构建高效可重复使用的视图模型.

假设我们正在编写Web应用程序.应用程序设计的要求之一是必须在每个页面上显示页面标题,用户名和应用程序名称.如果我们想创建一个页面以显示演示令对象,我们可以根据以下修改演示模型:

public class PresentationOrder
{
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }
    public int OrderID { get; set; }
    public DateTime OrderDate { get; set; }
    public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
    public string CustomerName { get; set; }
    public Decimal OrderAmount { get; set; }
    public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}

这个设计可能有效……但是如果我们想创建一个将显示订单列表的页面,那么怎么样?将重复PageTitle,用户名和ApplicationName属性,并变得笨重使用.此外,如果我们想在类的构造函数中定义某些页面级逻辑,何时何地?如果我们为每个将显示的每个订单创建实例,我们再也无法执行此操作.

组成在继承中

以下是我们可能重新定位订单呈现模型,使得它成为一个真实的视图模型,并且对显示单个呈现命令对象或呈现Order对象的集合有用:

public class PresentationOrderVM
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business properties
    public PresentationOrder Order { get; set; }
}


public class PresentationOrderVM
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business properties
    public List<PresentationOrder> Orders { get; set; }
}

查看上述两个类,我们可以看到一种思考视图模型的方法是它是一个包含另一个作为属性的演示模型的演示模型.顶级呈现模型(即查看模型)包含与页面或应用程序相关的属性,而演示模型(属性)包含与应用程序数据相关的属性.

我们可以更进一步地拍摄我们的设计,并创建一个基本视图模型类,该类不仅可以用于呈现,而且可以用于任何其他类:

public class BaseViewModel
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }
}

现在我们可以简化我们的帖子,如下所示:

public class PresentationOrderVM : BaseViewModel
{
    // Business properties
    public PresentationOrder Order { get; set; }
}

public class PresentationOrderVM : BaseViewModel
{
    // Business properties
    public List<PresentationOrder> Orders { get; set; }
}

我们可以通过使IT通用使我们的底映射更加可用:

public class BaseViewModel<T>
{
    // Application properties
    public string PageTitle { get; set; }
    public string UserName { get; set; }
    public string ApplicationName { get; set; }

    // Business property
    public T BusinessObject { get; set; }
}

现在我们的实现毫不费力:

public class PresentationOrderVM : BaseViewModel<PresentationOrder>
{
    // done!
}

public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
    // done!
}

以上所述是小编给大家介绍的什么是MVC中的ViewModel?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/34166.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。