为什么有两个类:视图模型和域模型?
我知道使用域模型作为视图模型可能很糟糕。如果我的域模型有一个名为 IsAdmin 的属性,并且我有一个创建控制器操作来创建用户,那么有人可以更改我的表单并使其 POST IsAdmin=true 表单值,即使我没有在视图中公开这样的文本字段。如果我使用模型绑定,那么当我提交域模型时,该人现在将成为管理员。因此,解决方案变成仅公开视图模型中所需的属性,并使用 AutoMapper 等工具将返回的视图模型对象的属性值映射到域模型对象的属性值。但我读到,类上的绑定属性可用于指示模型绑定器应该绑定哪些属性,不应该绑定哪些属性。那么,创建两个本质上代表同一事物的独立类(域模型和视图模型),然后在映射它们时产生开销的真正原因是什么?这更多的是一个代码组织问题吗?如果是的话,我有什么好处?
编辑
我遇到的视图模型与域模型分离的最重要原因之一是需要实现 MVVM 模式(基于 Martin Fowler 的 PM 模式)来管理复杂的 UI。
I know it could be bad to use domain models as view models. If my domain model has a property named IsAdmin and I have a Create controller action to create users, someone could alter my form and get it to POST a IsAdmin=true form value, even if I did not expose such a text field in my view. If I'm using model binding then when I committed my domain model, that person would now be an admin. So the solution becomes exposing just the properties I need in the view model and using a tool like AutoMapper to map the property values of my returning view model object to that of my domain model object. But I read that the bind attribute on a class can be used to instruct the Model Binder which properties it should and shouldn't bind. So what really is the reason for making two separate classes (domain model and view model) that essential represent the same thing and then incure overhead in mapping them? Is it more a code organization issue and if so, how am I benefiting?
EDIT
One of the most important reasons I've come across for a View Model that's separate from the Domain Model is the need to implement the MVVM pattern (based on Martin Fowler's PM pattern) for managing complex UIs.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我发现,虽然我的领域模型可以 85% 地获得我想要的字段,但它从未覆盖我视图中我想要的值的 100%。特别是当涉及到权限以及用户是否应该有权访问视图的某些部分时。
我试图遵循的设计理念是在我的观点中尽可能少的逻辑。这意味着我的视图模型中有“CanViewThisField”或“CanEditThisField”等字段。当我第一次开始使用 MVC 时,我会让我的域模型成为我的视图模型,并且我总是遇到这样的情况:我只需要一两个以上的字段来使我的视图不那么混乱。我已经去了 查看模型/模型生成器 路线,它对我来说非常有效。我不再与我的代码作斗争,而是能够根据需要增强我的视图模型,而不会影响域模型。
I have found that while my domain model gets me 85% of the way to having the fields I want, it has never covered 100% of the values I want on my view. Especially when it comes to permissions and whether or not a user should have access to certain portions of the view.
The design concept I attempt to follow is to have as little logic in my views as possible. This means I have fields in my view model like "CanViewThisField" or "CanEditThisField." When I first started with MVC I would have my domain model be my view model and I was always running into the scenario where I needed just one or two more fields to make my view less cluttered. I've since gone the View Model/Model Builder route and it has worked wonderfully for me. I don't battle my code any longer but am able to enhance my view model as I need to without affecting the domain model.
使用 ViewModel 的另一个好理由是对大量数据进行分页。您可以向视图传递一个 Person 数组 (
Person[]
),但页数、当前页数、页面大小等元数据不属于Person
类。因此,PersonListViewModel 可以解决这个问题。
Another good reason to have a ViewModel is paging large sets of data. You could pass the view an array of Person (
Person[]
) but metadata such as the number of pages, the number of the current page, the size of the page would not belong on thePerson
class.Therefore a PersonListViewModel would solve this issue.
ViewModel 仅包含视图所需的成员。它们通常可以被认为是底层领域模型的简化或“扁平化”。
像这样思考它们:
查看
有关此实体的信息,以便执行其所有功能
例如,我的 Order 类有一个名为 Customer 的成员,它是一个 组合 关联,即我的订单有 客户。该客户对象具有诸如名字、姓氏等成员...但是我如何在订单的“详细信息”视图或订单列表以及下订单的客户中显示它?
好吧,使用 ViewModel 我可以拥有一个 OrderListItemViewModel,它有一个 CustomerName 成员,并且我可以将 Firstname 和 Lastname 的组合从 Customer 对象映射到此。这可以手动完成,或者最好使用 Automapper 或类似工具完成。
使用这种方法,您可以拥有特定于不同视图的多个订单视图模型,例如,订单列表视图可能以与订单详细信息视图不同的方式呈现客户名称。
ViewModel 的另一个优点是,您可以减少视图上底层域对象不需要的无关数据,例如,如果我正在查看订单列表,我是否真的想查看所有客户的联系信息、账单详细信息、 ETC...?我想这取决于列表的目的,但可能不是。
A ViewModel holds only those members which are required by the View. They can usually be thought of as a simplification or a "flattening" of the underlying domain model.
Think of them like this:
view
about this entity in order to perform all it's functionality
For example, my Order class has a member called Customer which is a composition association, that is, my Order has a Customer. This Customer object has members such as Firstname, Lastname, etc... But how would I show this on a "details" view of the order or a list of Orders and the Customers who placed them?
Well, using a ViewModel I can have an OrderListItemViewModel which has a CustomerName member and I can map the combination of Firstname and Lastname from the Customer object to this. This can be done manually, or much preferably using Automapper or similar.
Using this approach, you can have multiple Order ViewModels that are specific to different views, e.g. the Order list view might render the customer name in a different way to the Order details view.
Another advantage of ViewModels is that you can cut down on extraneous data not required of the underlying domain object on a view, e.g. if I'm viewing a list of orders, do I really want to see all the customer's contact information, billing details, etc...? I guess that depends on the purpose of the list but, probably not.
有时您需要以特定方式显示数据(即,以 mm/dd/yyyy 与 yyyy/mm/dd 格式显示日期),并且通常在视图中而不是在域中设置此属性更容易模型,您将(或应该)在其中映射到数据库中的列。
Sometimes you need to display the data in a specific manner (ie, displaying a date in the format mm/dd/yyyy vs. yyyy/mm/dd) and often it is easier to make this property in the view and not in the domain model, where you would (or should) have a mapping to a column in your db.
你需要记住
您的
域模型类
仅在内部使用
;也就是说,它们永远不会被发送到客户。这就是您的服务模型类型(视图模型类型)的用途 - 它们表示将在客户端和您的服务之间来回传输的数据。
you need to remember
that your
domain model classes
are only usedinternally
; that is, they are never sent to theclient. That’s what your service model types (View Model types) are used for—they represent the data that will be going back and forth between the client and your service.