2014-11-23 63 views
0

我正在开发一个ASP.NET MVC应用程序,并且我遇到了一个非常尴尬的情况。ViewModels和ASP.NET MVC中的域模型

我有一个页面,用户可以通过一些标准搜索一些项目(比如学生)。我以前的学生集合传递给我的看法,但我已经添加了一些设置进行搜索,所以我已经决定要创建视图模型如下

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

然后我想过的情况时,我必须向每个学生添加一些额外的信息,这些信息并不存储在数据库中并在控制器上生成。我的第一个想法是很愚蠢的一个 - 我已经添加了额外的阵列将其保存在视图模型是这样的:

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. 一般来说,因为我已经明白,一个视图模型应该包括只有原语及其藏品(和可能,其他的ViewModels作为第一个问题)。这是对的吗?

回答

1

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

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

我相信是的。你的观点'包含''学生观点'列表。 Viewmodels仅用于以最佳方式构建数据来为视图提供视图,从而使视图中的必要逻辑尽可能最小化。

  1. 据我发现,ViewModel不应该包含域模型。

我建议不要在视图中使用您的实体,特别是在处理表单或其他数据输入方式时。在这种情况下,创建一个特殊的“表单模型”通常很有趣,该表单模型仅包含您希望用户提交的属性。这也允许你为这个特定的表单编写验证逻辑。将其视为服务于您的表单的模型,类似于视图模型如何服务于您的视图。使用AutoMapper来填充这些表单模型,使您的生活更轻松。但是,在某些情况下,我觉得在视图中使用实体是可以接受的:当您使用EF和延迟加载时,您可以在显示数据以从延迟加载机制中获利时使用实体。只有你显示的数据会从数据库中加载。但是,由于几乎总是事先知道您需要哪些数据,因此通常会有更好的数据加载策略。延迟加载在开发过程中非常方便,因为在进行大量更改时(加载&显示更快的数据更容易实现,无需更改大量代码),但通常是在性能评估过程中首先要解决的问题。

  1. 我应该将学生资产分成较小的资产吗?一般来说,正如我所理解的,ViewModel应该只包含原语及其集合(可能还包括其他ViewModel,如第一个问题)。这是对的吗?

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

这是我的2美分。

+0

谢谢。我唯一不完全理解的是你的第三个答案。参考你的第二个答案,我不应该在我的Views中使用任何领域模型(通常的Student,不是StudentViewModel)。然而,那么你说我实际上应该使用我的学生课。我是否正确地认为最好的方法是1)保持领域模型学生不变,2)使用StudentViewModel来满足视图的需求,而不是将其划分为不同的属性?另外,我对DTO条款不太满意。我的ViewModels可以被视为DTO吗? – 2014-11-24 18:42:12