我是ASP的新手。净MVC。我在理解ViewModel的目的方面有一个问题。

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

如果我能给出一个关于它的工作和解释的好例子,那就更好了。


当前回答

视图模型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和继承类的所有属性。

其他回答

视图模型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和继承类的所有属性。

If you want to study code on how to set up a "Baseline" web application with ViewModels I can advise you to download this code on GitHub: https://github.com/ajsaulsberry/BlipAjax. I developed large enterprise applications. When you do this it's problematic to set up a good architecture that handles all this "ViewModel" functionality. I think with BlipAjax you will have a very good "baseline" to start with. It's just a simple website, but great in its simplicity. I like the way they used the English language to point out what's really needed in the application.

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

视图模型是一个类,我们可以使用它在视图上呈现数据。假设您有两个实体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。

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

假设你有一个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; }
}

As you can see it only contains two of the properties. These two properties are also in the employee domain model. Why is this you may ask? Id might not be set from the view, it might be auto generated by the Employee table. And DateCreated might also be set in the stored procedure or in the service layer of your application. So Id and DateCreated are not needed in the view model. You might want to display these two properties when you view an employee’s details (an employee that has already been captured) as static text.

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

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个属性的域模型,而您只想更新一个值,那么您可以想象所有不必要的代码和验证。在这种情况下,视图模型中只有这个值/属性,而不是域对象中的所有属性。

A view model might not only have data from one database table. It can combine data from another table. Take my example above about adding a new employee record. Besides adding just the first and last names you might also want to add the department of the employee. This list of departments will come from your Departments table. So now you have data from the Employees and Departments tables in one view model. You will just then need to add the following two properties to your view model and populate it with data:

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

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

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

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