MVC 中的 ViewModel 是啥?

Posted

技术标签:

【中文标题】MVC 中的 ViewModel 是啥?【英文标题】:What is ViewModel in MVC?MVC 中的 ViewModel 是什么? 【发布时间】:2012-06-19 07:53:39 【问题描述】:

我是 ASP.NET MVC 的新手。我无法理解 ViewModel 的用途。

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

如果我能得到一个关于它的工作和解释的好例子会更好。

【问题讨论】:

这篇文章就是你要找的——“什么是 ASP.NET MVC ViewModel?” 这篇文章看起来很棒:rachelappel.com/… In MVC, what is a ViewModel?的可能重复 【参考方案1】:

view model 表示您希望在视图/页面上显示的数据,无论是用于静态文本还是用于可添加到数据库(或编辑)的输入值(如文本框和下拉列表) .它与您的domain model 不同。它是视图的模型。

假设您有一个代表您的员工域模型的Employee 类,它包含以下属性(唯一标识符、名字、姓氏和创建日期):

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 也可能设置在存储过程或应用程序的服务层中。所以视图模型中不需要IdDateCreated。当您将员工的详细信息(已被捕获的员工)作为静态文本查看时,您可能希望显示这两个属性。

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

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 MVCRazor 视图引擎):

@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>

因此仅在FirstNameLastName 上进行验证。使用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 表。所以现在您在一个视图模型中拥有来自EmployeesDepartments 表的数据。然后您需要将以下两个属性添加到您的视图模型并用数据填充它:

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 的 Id 从数据库中获取员工的数据。然后我会在我的视图/页面上显示静态文本,以便用户可以看到员工是什么被删除。当用户单击删除按钮时,我将使用 Id 值 3 并将其传递给我的存储库层。您只需要Id 从表中删除一条记录。

另外一点,你并不需要一个视图模型来处理每一个动作。如果是简单数据,那么只使用EmployeeViewModel 就可以了。如果它是复杂的视图/页面并且它们彼此不同,那么我建议您为每个视图使用单独的视图模型。

我希望这能消除您对视图模型和域模型的任何困惑。

【讨论】:

@Kenny:然后显示它:) 我想说的是,假设您有一个具有 50 个属性的域模型,而您的视图只需要显示 5 个,那么发送所有 50 个属性是没有用的属性只是为了显示 5. @BrendanVogt - 你很好地解释了这一点,但我不明白“发送所有 50 个属性”的成本是多少。其他代码已经创建了一个包含所有 50 个属性的 Model 对象,并且仅仅为了发送 45 个属性而维护另一个类似乎不值得——尤其是如果您可能想在未来发送这 45 个属性中的任何一个。 @BrendanVogt – 我想也许 LukLed 的回答可以帮助我理解为什么这些可能有用,特别是 ViewModel(可以)“......结合来自不同数据库实体的值”[我假设该短语与“数据库实体”替换为“模型对象”一样正确]。但是,ViewModel 打算解决哪些具体问题?你有任何链接吗?我自己什么都找不到。 [如果我似乎在挑剔你,我深表歉意!] 我刚刚听到有人说 ViewModels 是一种将多个集合(或跨模型属性)发送到单个视图中而无需将它们填充到 viewBag 中的好方法。对我来说很有意义。 我很抱歉批评,但不幸的是,这个答案是不完整的。将视图模型定义为仅需要在页面上显示的内容就像在问“什么是汽车?”并收到“它不是飞机”的回答。那是真的,但不是很有帮助。 VM 更正确的定义是“呈现页面所需的一切”。如果您向下阅读,我已经确定了正确、轻松地构建 VM 所需的组件,在许多情况下利用您现有的域模型和表示模型。【参考方案2】:

视图模型是一个类,表示特定视图中使用的数据模型。我们可以使用这个类作为登录页面的模型:

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; 

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

@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 的特定验证规则。 视图模型定义了视图的外观(对于LabelForEditorForDisplayFor 助手)。 视图模型可以组合来自不同数据库实体的值。 您可以轻松地为视图模型指定显示模板,并使用 DisplayFor 或 EditorFor 帮助器在许多地方重复使用它们。

另一个视图模型及其检索示例:我们想要显示基本用户数据、他的权限和用户名。我们创建了一个特殊的视图模型,它只包含必填字段。我们从数据库中检索不同实体的数据,但视图只知道视图模型类:

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
 

【讨论】:

我瘦 user.Mother.FirstName + " " + user.Mother.LastName 应该在 View Model End 中完成。所有逻辑都应该在 View Model 端完成。 @Chandana:我相信简单的连接可以在视图模型中完成。如果两个字段要一起显示,则没有理由公开它们。【参考方案3】:

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

http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development

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

总结并直接回答所提出的问题:

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

这里是实体模型(又名 DTO,又名模型)、表示模型和视图模型的比较。

数据传输对象又名“模型”

数据传输对象 (DTO) 是一个类,其属性与数据库中的表架构相匹配。 DTO 因其在数据存储中往返数据的常见用途而得名。 DTO 的特点:

是业务对象 - 它们的定义取决于应用程序数据。 通常只包含属性 - 没有代码。 主要用于在数据库之间传输数据。 属性与数据存储中特定表上的字段完全匹配或紧密匹配。

数据库表通常被规范化,因此 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 相同的属性,因此,它们经常会相互混淆。

视图模型的特征:

是用于呈现页面或屏幕的单一数据源。通常,这意味着视图模型将公开页面上的任何控件正确呈现自身所需的每个属性。使视图模型成为视图的单一数据源,极大地提高了其单元测试的能力和价值。 是复合对象,包含由应用程序数据和应用程序代码使用的属性组成的属性。在设计可重用视图模型时,这一特性至关重要,下面的示例将对此进行讨论。 包含应用程序代码。视图模型通常包含在渲染期间和用户与页面交互时调用的方法。此代码通常与事件处理、动画、控件的可见性、样式等有关。 包含调用业务服务以检索数据或将其发送到数据库服务器的代码。此代码经常被错误地放置在控制器中。从控制器调用业务服务通常会限制视图模型对单元测试的有用性。需要明确的是,视图模型本身不应包含业务逻辑,而应调用包含业务逻辑的服务。 通常包含属于其他页面或屏幕的其他视图模型的属性。 写成“每页”或“每屏”。通常为应用程序中的每个页面或屏幕编写一个唯一的视图模型。 通常从基类派生,因为大多数页面和屏幕都具有共同的属性。

查看模型组合

如前所述,视图模型是复合对象,因为它们将应用程序属性和业务数据属性结合在一个对象上。在视图模型上使用的常用应用程序属性示例如下:

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

以下示例说明了为什么视图模型的复合性质很重要,以及我们如何才能最好地构建一个高效且可重用的视图模型。

假设我们正在编写一个 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、UserName 和 ApplicationName 属性将重复使用,并且难以使用。另外,如果我们想在类的构造函数中定义一些页面级的逻辑呢?如果我们为每个将要显示的订单创建一个实例,我们就不能再这样做了。

组合优于继承

我们可以通过以下方式重构订单展示模型,使其成为真正的视图模型,并有助于显示单个 PresentationOrder 对象或 PresentationOrder 对象的集合:

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; 

查看上面的两个类,我们可以看到考虑视图模型的一种方式是它是一个表示模型,其中包含另一个表示模型作为属性。***表示模型(即视图模型)包含与页面或应用程序相关的属性,而表示模型(属性)包含与应用程序数据相关的属性。

我们可以更进一步,创建一个基础视图模型类,它不仅可以用于 PresentationOrders,还可以用于任何其他类:

public class BaseViewModel

    // Application properties
    public string PageTitle  get; set; 
    public string UserName  get; set; 
    public string ApplicationName  get; set; 

现在我们可以像这样简化我们的 PresentationOrderVM:

public class PresentationOrderVM : BaseViewModel

    // Business properties
    public PresentationOrder Order  get; set; 


public class PresentationOrderVM : BaseViewModel

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

我们可以通过将 BaseViewModel 设为通用来使其更具可重用性:

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!

【讨论】:

Sam 谢谢!!这帮助我完全掌握了一个多方面的实体:View-Model。我是一名刚刚学习 MVC 架构的大学生,这阐明了向开发人员公开的一系列强大功能。如果可以的话,我会在你的答案旁边加一颗星。 @Sam '视图模型通常包含与表示模型和 DTO 相同的属性,因此它们经常混淆彼此。'这是否意味着它们是常用而不是表示模型,或者它们是否旨在包含表示模型/dtos? @AlexanderDerck 它们用于不同的目的。他们混淆了另一个(错误)。不,您通常不会使用 pres 模型代替视图模型。更常见的是虚拟机“包含”表示模型,即MyViewModel&lt;MyPresModel&gt; @Sam 假设模型对象是活动对象,例如nhibernate模型..所以通过拥有BusinessObject我们不是将模型/活动对象直接暴露给视图吗?即业务对象可用于直接修改数据库状态?另外,嵌套视图模型呢?这需要多个业务对象属性,对吧? 由此看来,需要采取额外的步骤来从 EF 实体构建自己的表示模型,例如在数据库编辑的情况下,然后在保存之前采取进一步的额外步骤将其提炼回实体。这可以通过 AutoMapper 之类的东西来完成。我对你的理解正确吗?【参考方案4】:

如果您有特定于视图的属性,并且与 DB/服务/数据存储无关,那么使用 ViewModel 是一个很好的做法。比如说,您想根据一个(或两个)数据库字段选中一个复选框,但数据库字段本身不是布尔值。虽然可以在模型本身中创建这些属性并将其隐藏在与数据的绑定中,但您可能不希望根据此类字段和事务的数量使模型混乱。

如果视图特定的数据和/或转换太少,您可以使用模型本身

【讨论】:

【参考方案5】:

我没有阅读所有帖子,但每个答案似乎都缺少一个真正帮助我“明白”的概念......

如果 Model 类似于数据库 Table,那么 ViewModel 类似于数据库 View - 一个视图通常要么从一个表返回少量数据,要么从多个表(连接)返回复杂的数据集。

我发现自己使用 ViewModels 将信息传递到视图/表单中,然后在表单回发到控制器时将该数据传输到有效模型中 - 这对于存储列表(IEnumerable)也非常方便。

【讨论】:

【参考方案6】:

MVC 没有视图模型:它有模型、视图和控制器。视图模型是 MVVM(模型-视图-视图模型)的一部分。 MVVM 源自 Presentation Model,在 WPF 中得到普及。 MVVM 中也应该有一个模型,但大多数人完全忽略了该模式的要点,他们只会有一个视图和一个视图模型。 MVC 中的模型与 MVVM 中的模型类似。

在 MVC 中,该过程分为 3 个不同的职责:

View 负责将数据呈现给用户 控制器负责页面流 模型负责业务逻辑

MVC 不太适合 Web 应用程序。它是 Smalltalk 引入的一种用于创建桌面应用程序的模式。 Web 环境的行为完全不同。从桌面开发中复制一个 40 年前的概念并将其粘贴到 Web 环境中没有多大意义。然而很多人认为这没问题,因为他们的应用程序编译并返回正确的值。也就是说,在我看来,不足以宣布某个设计选择是好的。

Web 应用程序中的模型示例可能是:

public class LoginModel

    private readonly AuthenticationService authentication;

    public LoginModel(AuthenticationService authentication)
    
        this.authentication = authentication;
    

    public bool Login()
    
        return authentication.Login(Username, Password);
    

    public string Username  get; set; 
    public string Password  get; set; 

控制器可以这样使用它:

public class LoginController

    [HttpPost]
    public ActionResult Login(LoginModel model)
    
        bool success = model.Login();

        if (success)
        
            return new RedirectResult("/dashboard");
        
        else
        
            TempData["message"] = "Invalid username and/or password";
            return new RedirectResult("/login");
        
    

您的控制器方法和模型将很小、易于测试且切中要害。

【讨论】:

感谢您对MVVM架构的洞察,但是为什么MVC不行呢?你的推理是有问题的,并且怀疑是偏袒。诚然我对 MVVM 一无所知,但如果像 MVC 这样的架构可以模仿这种行为而无需编写 50k 行代码,那有什么大不了的? @Chef_Code:这不是问题或偏袒:只需阅读有关 MVC 的原始论文。回到源头比毫无疑问地盲目追随(又名“最佳实践”)要好得多。 MVC 适用于更小的单元:例如屏幕上的按钮由模型、视图和控制器组成。在 Web-MVC 中,整个页面有一个控制器、一个模型和一个视图。模型和视图应该是连接的,因此模型中的更改立即反映在视图中,反之亦然。模仿是一件大事。架构不应欺骗其开发人员。 @jeroen 首字母缩略词 MVC 已被盗用和损坏。是的,MVC 没有虚拟机,但它也没有存储库或服务层,这些对象在网站中被广泛使用。我相信 OP 是在问“我如何在 MVC 中引入和使用 VM”。在 MVC 的新含义中,模型不是业务逻辑所属的地方。业务逻辑属于使用 MVC 或 MVVM 的 Web 或桌面应用程序的服务层。术语模型描述了传入/传出服务层的业务对象。这些定义与 MVC 的原始描述大不相同。 @Sam 并非网站的所有内容都可以称为 MVC 的一部分。 MVC 没有新的含义。有正确的含义和“人们与 MVC 混淆的完全无关的东西”-含义。说模型负责业务逻辑,不等于业务逻辑编码在模型中。大多数时候,模型充当应用程序的外观。 我在微软的 MVC 中看到的主要缺陷是锁定了带有视图的模型。这本身就违背了过去 20 年来在 N 层设计中进行的所有这种分离的全部目的。他们浪费了我们的时间,迫使我们在 2002 年使用“WebForms”,这是另一个受桌面启发的模型,被提升到 Web 世界。现在他们已经抛弃了它,但又在这个新的 web 开发范式上提升了另一个桌面模型。与此同时,谷歌和其他公司正在构建将这一切分开的巨大客户端模型。我认为 1998 年的旧 ASP VBScript 是他们最真实的 Web 开发系统。【参考方案7】:

很多大的例子,让我解释清楚。

ViewModel = 为视图服务而创建的模型。

ASP.NET MVC 视图不能有多个模型,因此如果我们需要将多个模型的属性显示到视图中,这是不可能的。 ViewModel 服务于这个目的。

View Model 是一个模型类,它只能包含视图所需的那些属性。它还可以包含来自数据库的多个实体(表)的属性。顾名思义,这个模型是根据视图要求创建的。

下面是几个视图模型的例子

要在视图页面中列出来自多个实体的数据 – 我们可以创建一个 查看模型并拥有我们想要的所有实体的属性 列出数据。加入那些数据库实体并设置视图模型 属性并返回视图以显示不同的数据 一个表格形式的实体 视图模型只能定义单个实体的特定字段,即 视图所需的。

ViewModel 还可用于将记录插入、更新到多个实体中,但 ViewModel 的主要用途是将来自多个实体(模型)的列显示到单个视图中。

ViewModel的创建方式与Model的创建方式相同,ViewModel的View创建方式与Model的创建方式相同。

这是List data using ViewModel的一个小例子。

希望这会有用。

【讨论】:

【参考方案8】:

视图模型 a 是一个简单的类,它可以包含多个类属性。我们使用它来继承所有必需的属性,例如我有两个班级 Student 和 Subject

Public class Student

public int Id get; set;
public string Name get; set;
  
Public class Subject

public int SubjectID get; set;
public string SubjectName get; set;

现在我们想在视图中显示记录学生的姓名和学科的姓名(在 MVC 中),但不能添加多个类,例如:

 @model ProjectName.Model.Student  
 @model ProjectName.Model.Subject

上面的代码会报错...

现在我们创建一个类并且可以给它起任何名字,但是这种格式“XyzViewModel”会更容易理解。是继承的概念。 现在我们使用以下名称创建第三个类:

public class StudentViewModel:Subject

public int ID get; set;
public string Name get; set;

现在我们在 View 中使用这个 ViewModel

@model ProjectName.Model.StudentViewModel

现在我们可以在 View 中访问 StudentViewModel 和继承类的所有属性了。

【讨论】:

【参考方案9】:

ViewModel 是修补 MVC 框架概念上的笨拙的解决方法。它代表 3 层 Model-View-Controller 架构中的第 4 层。当 Model(领域模型)不合适,对于 View 来说太大(大于 2-3 个字段)时,我们创建较小的 ViewModel 将其传递给 View。

【讨论】:

【参考方案10】:

View Model 是我们可以用来在 View 上渲染数据的类。假设您有两个实体 Place 和 PlaceCategory,并且您想使用单个模型访问这两个实体的数据,那么我们使用 ViewModel。

  public class Place
    
       public int PlaceId  get; set; 
        public string PlaceName  get; set; 
        public string Latitude  get; set; 
        public string Longitude  get; set; 
        public string BestTime  get; set; 
    
    public class Category
    
        public int ID  get; set; 
        public int? PlaceId  get; set; 
        public string PlaceCategoryName  get; set; 
        public string PlaceCategoryType  get; set; 
    
    public class PlaceCategoryviewModel
    
        public string PlaceName  get; set; 
        public string BestTime  get; set; 
        public string PlaceCategoryName  get; set; 
        public string PlaceCategoryType  get; set; 
    

所以在上面的示例中 Place 和 Category 是两个不同的实体,PlaceCategory viewmodel 是我们可以在 View 上使用的 ViewModel。

【讨论】:

你的例子不是很清楚。上面所说的是 ViewModel 将数据连接到它的视图。如果您查看 BlipAjax 中的 ViewModel,您会看到非常适合它的类。【参考方案11】:

视图模型是数据的概念模型。例如,它的用途是获取子集或组合来自不同表的数据。

您可能只需要特定的属性,因此这允许您只加载那些而不是其他不必要的属性

【讨论】:

【参考方案12】: ViewModel 包含在视图中表示的字段(对于 LabelFor、EditorFor、DisplayFor 助手) ViewModel 可以使用数据注释具有特定的验证规则 或 IDataErrorInfo。 ViewModel 可以有来自不同数据的多个实体或对象 模型或数据源。

设计视图模型

public class UserLoginViewModel 
 
[Required(ErrorMessage = "Please enter your username")] 
[Display(Name = "User Name")]
[MaxLength(50)]
public string UserName  get; set; 
 [Required(ErrorMessage = "Please enter your password")]
 [Display(Name = "Password")]
 [MaxLength(50)]
 public string Password  get; set;  
 

在视图中展示视图模型

@model MyModels.UserLoginViewModel 
@
 ViewBag.Title = "User Login";
 Layout = "~/Views/Shared/_Layout.cshtml";

@using (Html.BeginForm())

<div class="editor-label">
 @Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
 @Html.TextBoxFor(m => m.UserName)
 @Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
 @Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
 @Html.PasswordFor(m => m.Password)
 @Html.ValidationMessageFor(m => m.Password)
</div>
<p>
 <input type="submit" value="Log In" />
</p>
</div>

使用行动

public ActionResult Login()
 
return View();

[HttpPost]
public ActionResult Login(UserLoginViewModel user)

// To acces data using LINQ
DataClassesDataContext mobjentity = new DataClassesDataContext();
 if (ModelState.IsValid) 
 
try
 
 var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList(); 
 if (q.Count > 0) 
  
 return RedirectToAction("MyAccount");
 
 else
 
 ModelState.AddModelError("", "The user name or password provided is incorrect.");
 
 
 catch (Exception ex)
 
  
  
 return View(user);
 
    在 ViewModel 中只放置您想要显示的那些字段/数据 视图/页面。 由于视图代表 ViewModel 的属性,因此它是 易于渲染和维护。 当 ViewModel 变得更复杂时使用映射器。

【讨论】:

【参考方案13】:

如果您想学习如何使用 ViewModels 设置“基线”Web 应用程序的代码,我可以建议在 GitHub 上下载此代码:https://github.com/ajsaulsberry/BlipAjax。我开发了大型企业应用程序。当你这样做时,设置一个处理所有这些“ViewModel”功能的良好架构是有问题的。我认为使用 BlipAjax,您将拥有一个非常好的“基线”。它只是一个简单的网站,但非常简单。我喜欢他们使用英语来指出应用程序中真正需要什么的方式。

【讨论】:

【参考方案14】:

ViewModel 是包含要在 mvc View 中使用的字段的模型。为视图使用 ViewModel 有以下好处:

由于数据库模型(实体类)包含单个表的数据。如果需要来自多个表的数据,单个 Viewmodel 可以有多个表的字段。 用户不能直接与数据库模型交互,因此数据库层或模型是安全的。 用于通过存储库从数据库模型中获取数据并传递给视图。同样,它利用将数据发布到数据库模型来更新数据库记录。

【讨论】:

【参考方案15】:

视图模型与您的数据模型相同,但您可以在其中添加 2 个或更多数据模型类。据此,您必须更改控制器以一次获取 2 个模型

【讨论】:

以上是关于MVC 中的 ViewModel 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

MVVM你到底由多少秘密

Mvc 列出嵌套在 Viewmodel 中的多个视图

Android ViewModel 不断初始化 ArrayList

Android Jetpack - ViewModel

Android Jetpack - ViewModel

Android Jetpack - ViewModel