我们只是在控制器中获取实体,并将它们作为模型发送到视图,这导致视图代码要求数据库获取我们正在使用的导航属性.我们已经看过这个,看起来不是一个好的设计,但是我们想知道为什么?
你能帮我们理解这个设计问题吗?
谢谢!
解决方法
+---------------------------------------> Views | | | | | v Controllers ----+-> Model Transformer -----> View Model | \ | | \ | v \ v Data Access <---- Persistence --------> Domain Model | / | / v / Mapper ------+
现在我意识到说“这里是一个架构,这是你应该使用的”并不完全令人信服,所以让我来解释一下这里发生了什么:
>控制器接收请求.
>控制器调用某种持久层(即存储库).
>持久层检索数据,然后使用映射器映射到域模型.
>控制器使用变压器将域模型更改为视图模型.
>控制器选择必要的视图并应用视图模型.
那么为什么这么好?
>域模型没有依赖关系.这是一件非常好的事情,这意味着执行验证,写测试等很容易.这意味着您可以在架构中的任何地方更改任何内容,并且永远不会破坏模型.这意味着您可以跨项目重用该模型.
>持久层返回域模型的实例.这意味着它可以被建模为一个完全抽象的,与平台无关的界面.需要使用持久层(例如控制器)的组件不承担任何其他依赖关系.这是理想的持续层的依赖注入,再次是可测试性.持久性,数据访问和映射器的组合可以生成在其自己的程序集中.在较大的项目中,您甚至可以进一步解析映射器并使其在通用记录集上运行.
>控制器只有两个下游依赖关系 – 域模型和持久层.该模型很少会改变,就像您的业务模式一样,由于持久化层是抽象的,所以几乎不需要更改控制器(添加新操作除外).
>视图取决于单独的UI模型.这使它们免受域模型的变化.这意味着如果您的业务逻辑更改,则不需要更改项目中的每个视图.它允许视图“看起来”应该是“愚蠢的” – 它们不仅仅是视图数据的占位符.这也意味着使用不同类型的UI(即智能客户端应用程序)重新创建视图或切换到不同的视图引擎(Spark,NHaml等)应该很简单,
现在,当使用诸如Linq的O / R映射器到sql或实体框架时,将它们生成的类视为域模型是非常诱人的.它看起来像一个域模型,但它不是.为什么?
>实体类与您的关系模型相关联,随着时间的推移,您的关系模型将与您的领域模型大相径庭;
实体类是哑的.很难支持任何复杂的验证场景或集成任何业务规则.这被称为贫血域模型.
>实体类具有隐藏的依赖关系.虽然它们似乎是普通的POCO,但它们实际上可能隐藏了对数据库的引用(即延迟关联的加载).这可能会导致数据库相关的问题引起视图逻辑,您最不能正确地分析发生了什么并进行调试.
>但最重要的是,“领域模式”不再是独立的.它不能生活在任何程序集的数据访问逻辑之外.那么可以这样做,如果你真的在工作,有办法去做,但这不是大多数人这样做的方式,即使你这样做,你会发现域的实际设计模型被限制到您的关系模型,特别是EF的行为.最重要的是,如果您决定更改持久性模型,则会破坏域模型,而您的域模型是应用程序中其他所有内容的基础.
实体框架类不是域模型.它们是数据关系模型的一部分,并且具有与域模型中的类相同或相似的名称.但依赖管理方面却是世界分明的.使用从ORM工具生成的类作为域模型只能导致非常脆弱的架构/设计;您对应用程序的几乎任何部分所做的每个更改都将具有一系列可预测和不可预测的级联效应.
有很多人似乎认为你不需要一个凝聚力,独立的领域模型.通常的借口是(a)它是一个小项目,和/或(b)他们的领域模型真的没有任何行为.但小项目变大,业务规则变得越来越复杂,一个贫穷或不存在的域名模型不是简单的重构.
这实际上是实体模型设计中最阴险的特征;似乎工作正常,一段时间.当你淹没在缺陷报告和变更请求中时,你不会发现这是一个错误,直到一年或两年,而拼命地将真正的领域模型拼凑在一起.