【问题标题】:Why Two Classes, View Model and Domain Model?为什么有两个类,视图模型和域模型?
【发布时间】:2011-06-19 10:40:18
【问题描述】:

我知道将域模型用作视图模型可能很糟糕。如果我的域模型有一个名为 IsAdmin 的属性并且我有一个创建控制器操作来创建用户,那么即使我没有在我的视图中公开这样的文本字段,也有人可以更改我的表单并让它发布一个 IsAdmin=true 表单值.如果我使用模型绑定,那么当我提交我的域模型时,那个人现在将成为管理员。因此,解决方案变成只在视图模型中公开我需要的属性,并使用 AutoMapper 之类的工具将我返回的视图模型对象的属性值映射到我的域模型对象的属性值。但我读到类的绑定属性可用于指示模型绑定器应该绑定和不应该绑定哪些属性。那么,创建两个独立的类(域模型和视图模型)的真正原因是什么,它们本质上代表相同的事物,然后在映射它们时会产生开销?这是否更像是一个代码组织问题?如果是,我有什么好处?

编辑

对于与域模型分离的视图模型,我遇到的最重要的原因之一是需要实现 MVVM 模式(基于 Martin Fowler 的 PM 模式)来管理复杂的 UI。

【问题讨论】:

标签: asp.net-mvc-3 model viewmodel modelbinders


【解决方案1】:

我发现,虽然我的域模型让我获得了我想要的字段的 85%,但它从来没有覆盖 100% 的我想要的值。尤其是在涉及权限以及用户是否应该有权访问视图的某些部分时。

我试图遵循的设计理念是在我的观点中尽可能少地包含逻辑。这意味着我的视图模型中有字段,例如“CanViewThisField”或“CanEditThisField”。当我第一次开始使用 MVC 时,我会将我的域模型作为我的视图模型,并且我总是遇到这样的场景:我只需要一个或两个字段来使我的视图不那么混乱。从那以后我就选择了View Model/Model Builder 路线,它对我来说非常有效。我不再与我的代码作斗争,但能够在不影响域模型的情况下根据需要增强我的视图模型。

【讨论】:

  • 我同意让视图不那么混乱,但是我们不能将这种类型的功能抽象到域模型而不是视图模型吗?我之前说过,但我不能在我的域模型上使用 DisplayAddress() 函数来组合域属性,如地址、城市、州和邮编吗? db 只映射属性而不是函数。
  • 显然一切皆有可能,只是取决于你想走哪条路。我为我生成了我的域模型,所以我并没有真正触及该代码。如果您使用任何类型的 ORM,那么就是这种情况。视图模型在不影响性能的情况下为我提供了最大的灵活性。
  • 抱歉,直到现在我才点击您提供的链接。我得出的结论是,决定是否采用 domain-model-view-model 路线取决于领域模型的需求。我可以看到我的一些域模型对象将如何使用视图模型,而有些则不会(尽管这可能会让某些人感到困惑——我会考虑更多)。不管怎样,我有我的答案。谢谢大家!
  • 我现在没有使用 ORM,但我很快就会使用。我知道我可以在类型化视图中使用 EntityFramework 类,但我不确定如果自动生成的类会不断被删除,我将如何装饰它们?!?感谢您的提醒。
  • @enamrik 如果您需要装饰自动生成的类,您可以使用部分类或“伙伴类”。
【解决方案2】:

有时您需要以特定方式显示数据(即,以 mm/dd/yyyy 与 yyyy/mm/dd 格式显示日期)并且通常更容易在视图中创建此属性,而不是在域模型中,您将(或应该)映射到数据库中的列。

【讨论】:

  • 谢谢,这很有道理。但是,我们不能只在域模型上创建函数来做到这一点吗?像 DisplayAddress() 一样,它结合了地址、城市、州和邮编等域属性? db 只映射属性而不是函数。这个想法是否违反了某些设计理念?
  • 在某种程度上,是的。如果您真的愿意,您可以在域模型中完成所有这些操作,并且效果一样。但是,我从来没有见过它在维护中工作得很好。通常,我已经看到将这些东西放入视图模型(或您正在使用的任何表示模型)中。所以说真的,这只是一个组织问题。 :)
【解决方案3】:

拥有 ViewModel 的另一个好理由是对大量数据集进行分页。您可以向视图传递一个 Person (Person[]) 数组,但元数据(例如页数、当前页数、页面大小)不属于 Person 类。

因此,PersonListViewModel 可以解决这个问题。

【讨论】:

    【解决方案4】:

    ViewModel 仅包含 View 所需的那些成员。它们通常可以被认为是底层域模型的简化或“扁平化”。

    这样想他们:

    • ViewModel:这是适合在此上呈现的数据 查看
    • 域模型:这是我的应用程序需要的所有信息 关于该实体以执行其所有功能

    例如,我的 Order 类有一个名为 Customer 的成员,它是一个 composition 关联,也就是说,我的 Order 有一个 Customer。此 Customer 对象具有 Firstname、Lastname 等成员...但是我如何在订单的“详细信息”视图或订单列表和下达订单的客户列表中显示这一点?

    好吧,使用 ViewModel 我可以拥有一个 OrderListItemViewModel,它有一个 CustomerName 成员,我可以将 Firstname 和 Lastname 的组合从 Customer 对象映射到这个。这可以手动完成,或者最好使用Automapper 或类似方法。

    使用这种方法,您可以拥有多个特定于不同视图的订单视图模型,例如订单列表视图可能会以与订单详细信息视图不同的方式呈现客户名称。

    ViewModels 的另一个优点是您可以减少视图上底层域对象不需要的无关数据,例如如果我正在查看订单列表,我是否真的想查看所有客户的联系信息、账单明细等...?我想这取决于列表的目的,但可能不是。

    【讨论】:

      【解决方案5】:

      你需要记住 您的 domain model classes 仅用于 internally;也就是说,它们永远不会被发送到 客户。这就是您的服务模型类型(视图模型类型)的用途——它们代表将在客户端和您的服务之间来回传输的数据。

      【讨论】:

        猜你喜欢
        • 2012-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 2011-11-07
        • 2013-05-27
        • 1970-01-01
        相关资源
        最近更新 更多