ASP.NET MVC 中的视图模型和域模型

本文关键字:模型 视图 NET MVC ASP | 更新日期: 2023-09-27 18:31:42

我正在开发一个 ASP.NET 的MVC应用程序,我遇到了一个非常尴尬的境地。

我有一个页面,用户可以在其中按某些条件搜索某些项目(例如,学生)。我曾经将一组学生传递给我的视图,但后来我添加了一些设置来搜索,所以我决定创建 ViewModel,如下所示

public class SearchViewModel
{
    public string SearchString { get; set; }
    public bool IsCaseSensitive { get; set; }
    ...
    //other parameters
    ...
    public IEnumerable<Student> Students { get; set; }
}

然后我想到了我必须为每个学生添加一些附加信息的情况,这些信息不存储在数据库中,而是在控制器上生成。我的第一个想法是相当愚蠢的 - 我添加了一个额外的数组来将其保存在 ViewModel 中,如下所示:

public class SearchViewModel
{
    public string SearchString { get; set; }
    public bool IsCaseSensitive { get; set; }
    ...
    //other parameters
    ...
    public IEnumerable<Student> Students { get; set; }
    public IEnumerable<int> someData { get; set; }
}

因此,要获取数据,客户端代码必须获取学生在数组中的位置,然后转到 someData 数组中的相应位置。

我不太喜欢这个想法,所以我将我的模型更改为包含搜索参数 + 一个额外的模型来保存学生对象及其数据。

public class SearchViewModel
{
    public string SearchString { get; set; }
    public bool IsCaseSensitive { get; set; }
    ...
    //other parameters
    ...
    public IEnumerable<StudentViewModel> StudentModels { get; set; }
}
public class StudentViewModel
{
    public Student Student { get; set; }
    public int someData { get; set; }
}
  1. 创建像StudentViewModel这样的"帮助程序"模型是个好主意吗?我可能不会在任何地方使用StudentViewModel,而是在SearchViewModel内部。鉴于SearchViewModel本身就是一种"帮助"模型,创建另一个仅在SearchViewModel内部使用的模型似乎有点奇怪。是这样吗?

  2. 据我所知,ViewModel 永远不应该包含域模型。我应该将学生财产划分为较小的财产吗?例如,像这样:

    public class StudentViewModel
    {
        public string Name { get; set; }
        public int GroupId { get; set; }
        public int someData { get; set; }
    }
    
  3. 一般来说,正如我所理解的,ViewModel 应该包含基元及其集合(可能还有其他 ViewModels,如第一个问题)。正确吗?

ASP.NET MVC 中的视图模型和域模型

我不假装这个不可侵犯的真理。但在我看来:

  1. 通常,视图模型只为一个视图创建。
  2. 在视图中使用域/数据模型通常是(如果它使开发过程更容易/更快/更清晰)。在您的情况下,我不会在视图模型中使用学生类。
  3. ViewModel 应包含构建视图所需的所有数据(基元和非基元)。但是,如果您可以通过在控制器中执行一些工作来使视图模型更容易、更清晰,那么应该完成它。
  1. 创建像StudentViewModel这样的"帮助程序"模型是个好主意吗?

我相信是的。您的视图"包含"一系列"学生观点"。视图模型的存在只是为了向视图提供以最佳方式结构化的数据,以便视图中的必要逻辑尽可能少。

  1. 据我所知,ViewModel 永远不应该包含域模型。

我建议不要在视图中使用您的实体,尤其是在处理表单或其他数据输入方式时。在这种情况下,创建一个特殊的"表单模型"通常很有趣,该模型仅包含您希望用户提交的属性。这还允许您为此特定表单编写验证逻辑。将其视为为窗体提供服务的模型,类似于视图模型为视图提供服务的方式。使用自动映射器填充这些表单模型,让您的生活更轻松。

但是,在某些情况下,我发现在您的视图中使用实体是可以接受的:使用 EF 和延迟加载时,可以在显示数据时使用实体,以便从延迟加载机制中受益。只有您显示的数据才会从数据库中加载。但是,由于几乎总是事先知道您需要哪些数据,因此通常有更好的数据加载策略。在开发过程中,当发生大量更改时,延迟加载很方便(加载和显示附加数据快速且易于实现,无需更改太多代码),但通常是性能评估期间要解决的第一件事。

  1. 我应该将学生财产划分为较小的财产吗?一般来说,正如我所理解的,ViewModel 应该只包含基元及其集合(可能还有其他 ViewModels,如第一个问题)。正确吗?

我不同意。您设计了表示业务对象的域,为什么要在视图模型中再次将其丢弃?始终考虑将来需要使用额外属性扩展域模型的可能性,以及您现在可以做些什么来降低此类更改的成本。如果要将域层与表示层分开,请引入包含相同对象的 DTO 层。在这些对象上,您可以应用数据注释和其他仅适用于表示层的内容。使用AutoMapper可以快速完成从域对象填充DTO。但是,请注意不要在这些 DTO 上/使用这些 DTO 编写您的业务逻辑。

这是我的2美分。