为什么在MVC中将实体作为模型传递不是一个好主意? [英] Why it's not a good idea to pass entities as Models in MVC?

查看:60
本文介绍了为什么在MVC中将实体作为模型传递不是一个好主意?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用MVC 2 RC2开发一个相当大的应用程序,并且我们收到了一些有关使用实体框架的延迟加载方式的反馈.

We're developing a pretty large application with MVC 2 RC2 and we've received some feedback on the way we're using the Entity Framework's Lazy Loading.

我们只是在控制器中获取实体,并将其作为模型发送到视图,这导致视图代码向数据库询问我们在其中使用的导航属性.我们已经读过这本书,看来它不是一个好的设计,但是我们想知道为什么吗?

We're just getting the entities in the controller and sending them as models to the Views, that is causing that the view code asks the Database for the navigation properties we are using in it. We have read about this and it appears is not a good design, but we were wondering why?

您能帮助我们了解此设计问题吗?

Can you help us understand this design problem?

谢谢!

推荐答案

此处的主要问题是耦合. 模型(即"MVC"中的"M")背后的想法是,它没有外部依赖性.它是您应用程序的核心".设计良好的应用程序体系结构的依赖关系树应如下所示:

The main issue here is coupling. The idea behind a model, which is the "M" in "MVC", is that it has no external dependencies. It is the "core" of your application. The dependency tree of a well-designed app architecture should look something like this:


                       +---------------------------------------> Views
                       |                                           |
                       |                                           |
                       |                                           v
                  Controllers ----+-> Model Transformer -----> View Model
                       |           \         |
                       |            \        |
                       v             \       v
Data Access <---- Persistence --------> Domain Model
                       |             /
                       |            /
                       v           /
                     Mapper ------+

现在我意识到仅仅说这是一种架构,这就是您应该使用的东西"并不完全令人信服,所以让我解释一下这里发生的事情:

Now I realize it's not exactly convincing to just say "here's an architecture, this is what you should use", so let me explain what's happening here:

  1. 控制器收到请求.
  2. 控制器调出某种持久层(即存储库).
  3. 持久层检索数据,然后使用映射器映射到域模型.
  4. 控制器使用转换器将域模型更改为视图模型.
  5. 控制器选择必要的视图并对其应用视图模型.

那么,为什么这样好呢?

So, why is this good?

  • 域模型没有没有依赖项.这是一件非常好的事情,这意味着执行验证,编写测试等操作很容易.这意味着您可以在体系结构中的任何地方进行任何其他更改,并且永远不会破坏模型.这意味着您可以在项目之间重用模型.

  • The domain model has no dependencies. This is a very good thing, it means that it's easy to perform validation, write tests, etc. It means that you can change anything else anywhere in your architecture and it will never break the model. It means that you can reuse the model across projects.

持久层返回域模型的实例 .这意味着可以将其建模为完全抽象的,与平台无关的接口.需要使用持久层的组件(例如控制器)不会承担任何其他依赖项.这对于持久层的依赖注入以及可测试性来说都是理想的.持久性,数据访问和映射器的组合可以存在于其自己的程序集中.在大型项目中,您甚至可以进一步解耦映射器,并使其在通用记录集上运行.

The persistence layer returns instances of the domain model. The means that it can be modeled as a totally abstract, platform-agnostic interface. A component that needs to use the persistence layer (such as the controller) does not take on any additional dependencies. This is ideal for Dependency Injection of the persistence layer and, again, testability. The combination of persistence, data access, and mapper can live in its own assembly. In larger projects you might even be able to further decouple the mapper and have it operate on a generic record set.

Controller仅具有两个下游依赖项-域模型和持久层.该模型应该很少更改,因为这就是您的业务模型,并且由于持久层是抽象的,因此几乎无需更改控制器(添加新操作除外).

The Controller only has two downstream dependencies - the domain model and the persistence layer. The model should rarely change, as that is your business model, and since the persistence layer is abstract, the controller should almost never need to be changed (except to add new actions).

视图依赖于单独的UI模型.这样可以使它们与域模型的更改隔离.这意味着,如果您的业务逻辑发生了变化,则无需更改项目中的每个视图.它允许视图像视图一样是哑"的-它们只不过是视图数据的占位符而已.这也意味着使用其他类型的UI(即智能客户端应用)重新创建视图,或切换到其他视图引擎(Spark,NHalml等)应该很简单

The Views depend on a separate UI model. This insulates them from changes in the domain model. It means that if your business logic changes, you do not need to change every single view in your project. It allows the views to be "dumb", as views should be - they are not much more than placeholders for view data. It also means that it should be simple to recreate the view using a different type of UI, i.e. a smart client app, or switch to a different view engine (Spark, NHaml, etc.)

现在,当使用Linq to SQL或Entity Framework等O/R映射器时,很容易将它们生成的类视为您的域模型.它看上去看起来像域模型,但事实并非如此.为什么?

Now, when using O/R Mappers such as Linq to SQL or Entity Framework, it is very tempting to treat the classes they generate as your domain model. It certainly looks like a domain model, but it is not. Why?

  • 实体类与您的关系模型相关联,随着时间的推移,它们可能会并且将与您的领域模型大相径庭;

  • The entity classes are tied to your relational model, which over time can and will diverge significantly from your domain model;

实体类很笨.支持任何复杂的验证方案或集成任何业务规则都是困难的.这称为贫血域模型.

The entity classes are dumb. It is difficult to support any complex validation scenarios or integrate any business rules. This is referred to as an anemic domain model.

实体类具有隐藏的依赖关系.尽管它们可能看起来像是普通的POCO,但实际上它们可能具有对数据库的隐藏引用(即,关联的延迟加载).最终可能导致与数据库相关的问题冒泡到视图逻辑中,在该视图逻辑中,您最不能够正确分析正在发生的事情并进行调试.

The entity classes have hidden dependencies. Although they may appear to be ordinary POCOs, they may in fact have hidden references to the database (i.e. lazy loading of associations). This can end up causing database-related issues to bubble up to the view logic, where you are least able to properly analyze what's going on and debug.

但最重要的是,域模型"不再独立.它不能存在于具有数据访问逻辑的任何程序集之外.嗯,这是可以的,如果您真的在工作,有很多方法可以解决这个问题,但这并不是大多数人这样做的方法,即使您做到了,您也会发现真正的设计领域的仅限于您​​的关系模型,尤其是EF的行为方式.最重要的是,如果您决定更改持久性模型,则会破坏域模型,而域模型是您应用中其他一切的基础.

But most importantly of all, the "domain model" is no longer independent. It cannot live outside whatever assembly has the data access logic. Well, it sort of can, there are ways to go about this if you really work at it, but it's not the way most people do it, and even if you pull this off, you'll find that the actual design of the domain model is constrained to your relational model and specifically to how EF behaves. The bottom line is that if you decide to change your persistence model, you will break the domain model, and your domain model is the basis for just about everything else in your app.

实体框架类不是不是域模型.它们是数据关系模型的一部分,并且碰巧具有与域模型中的类相同的名称.但是它们在依赖性管理方面是天壤之别.使用从ORM工具生成的类作为您的域模型只能导致极其脆弱的体系结构/设计.您对应用程序的几乎任何部分所做的每次更改都会产生一系列可预测和不可预测的级联效应.

Entity Framework classes are not a domain model. They are part of a data-relational model and happen to have the same or similar names that you might give to classes in a domain model. But they are worlds apart in terms of dependency management. Using classes generated from an ORM tool as your domain model can only result in an extremely brittle architecture/design; every change you make to almost any part of the application will have a slew of predictable and unpredictable cascade effects.

许多人似乎认为您不需要内聚的,独立的领域模型.通常的借口是(a)这是一个小项目,和/或(b)他们的域模型实际上没有任何行为.但是,小型项目变大了,业务规则变得越来越复杂,贫乏的或不存在的域模型不是您可以简单地重构的东西.

There are a lot of people who seem to think that you don't need a cohesive, independent domain model. Usually the excuse is that (a) it's a small project, and/or (b) their domain model doesn't really have any behaviour. But small projects become large, and business rules become (far) more complicated, and an anemic or nonexistent domain model isn't something you can simply refactor away.

实际上,这是实体作为模型设计的最阴险的特性; 似乎可以正常工作一段时间.直到一两年后,当您陷入缺陷报告和变更请求而拼命拼凑真正的领域模型时,才发现这有多大错误.

That is in fact the most insidious trait of the entities-as-model design; it seems to work fine, for a while. You won't find out how much of a mistake this is until a year or two down the road when you're drowning in defect reports and change requests while desperately trying to put together a real domain model piecemeal.

这篇关于为什么在MVC中将实体作为模型传递不是一个好主意?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆