您可以随意调用客户端实体类:-)
更严肃地说,让我们来看看声称这是一种反模式背后的典型原因。
客户端不是表示层
我想非常清楚这一点。 Breeze 专为富 Web 客户端应用程序设计。 Breeze 客户端不是表示层;它有一个表示层。它还拥有自己的业务模型和数据访问层。
术语“实体”和“DTO”对不同的人有不同的含义。我喜欢 Evan's DDD definition 代表“实体”,而 Fowler's definition for "DTO" 代表 PoEAA。
Breeze 客户端实体符合 Evans 实体的条件:“具有贯穿时间和不同表示的独特身份的对象。您还会听到这些称为“参考对象””[Fowler]。 Breeze 实体不仅仅是财产包;它们也有业务逻辑,您可以使用更多自己的逻辑来扩展它们。
Breeze 实体不是“展示模型”。它们独立于任何特定的 UI 表示,并且通常不实现表示问题。
它们的设计可以直接绑定到可视控件。这是 Breeze 生产力设计决策……关于我们如何实现实体的决策。有些人——那些认为实体属性是反模式的人——会讨厌这一点。埃文斯对这个问题保持沉默。 Fowler poo-poos it。如果它冒犯了你,你可能不喜欢微风。继续前进。
发送实体或 DTO?
我要争辩说这是一种错误的二分法。
人们经常说“通过网络发送实体是一种反模式。总是发送 DTO”。这个措辞不佳的法令背后有充分的理由。当客户端和服务器实体类相同时,您已将服务器的实现与客户端的实现耦合。如果模型在服务器上更改,它必须在客户端更改,反之亦然,即使更改仅与其中一个层相关。这可能会干扰您独立发展服务器和客户端代码的能力。我们可能会接受这种耦合作为一种权宜之计(而且权宜之计很重要!),但没有人想要它。
Breeze client 实体类不必与 server 实体类相同,无论是形状还是业务逻辑 .当您在 Breeze 中查询时,您将实体数据在线上并将其转换为客户端实体;保存时,将客户端实体 data 放在网络上,并将其在服务器上转换为服务器实体。 DTO 可能涉及任一方向。重要的事实是类可以不同。
当然,它们在概念上是相关的。如果Customer 实体的含义在两侧大相径庭,您将很难在两种表示之间转换数据。无论有没有明确的 DTO,都是如此。
我们还要承认,当类实际上相同时,在两个方向上转换数据会更容易。当它们不同时,您需要支付映射税,并且您可能会失去在客户端上编写 Breeze LINQ 查询的能力。如果你愿意,你可以交税。微风不在乎。
我倾向于从双方相同的课程开始,并在必要时更改它们。这对于 RIA Services 和 DevForce 中的大部分课程都非常有效。最重要的是,在需要时重新分解为单独的类对我来说从来都不是难事。
担忧夸大了共享类定义的风险,并低估了映射层的成本,其好处在应用程序的生命周期中很少在实践中实现。
何时使用演示模型
你写道:
对于图形深入到五个或六个级别的大型系统,需要将实体转换为 DTO 以使其变得简单。 ...大多数时候,这些 DTO 将代表 UI 想要的内容,并且相当于一个演示模型
根据我的经验,只有当您假设您的客户只是将实体粘贴到屏幕上时,这才是正确的。但是我已经规定了客户端是一个应用程序,而不是表示层。
我进一步认为,您在客户端需要域模型的原因与在服务器上需要域模型的原因相同:对域进行推理。您可以独立于演示文稿执行此操作。我假设您的实体将以某种方式出现在多个屏幕上,并遵循不同的呈现规则。它是相同的模型,呈现出多种方式。我们称之为“围绕数据旋转”。
无论您在模型上放置多少张面孔,基础模型数据和管理它们的业务规则都应该保持不变。这就是使它成为“领域模型”而不是“演示模型”的原因。
FWIW,我的应用程序中总是有一个“演示模型”(又名“ViewModel”)来编排视图的活动。所以我不会问自己“PM还是模特?”。相反,我选择 要么 将可视控件直接数据绑定到我通过 VM 的 api 公开的模型实体或 我将它们绑定到中间“项目表示模型”(AKA “包装一些实体的项目 ViewModel")。我走哪条路是申请决定。在实践中,我首先直接绑定到实体,然后在需要时重构为“Item ViewModel”。
无论哪种情况,我都会在客户端上构建我需要的 PM (VM)。如果我需要一个“Item ViewModel”,我也会在客户端上创建它。 我不要求我的服务器为我的客户端显示 DTO。 对我来说 这是一种反模式,因为它将服务器与客户端耦合。
怎么样?如果开发人员需要更改客户端上的屏幕,她可能必须等待有人提供支持的服务器端点和 DTO。现在我们必须协调服务器和客户端的发布时间表,即使改变的动力是客户端要求,而不是服务器要求。
服务污染
实际上比这更糟。一些服务器端开发人员不得不停止她正在做的事情并添加一个新的服务方法来满足客户的需求。这不是她的要求之一……但现在是。随着时间的推移,服务 API 得到了极大的扩展,很快就充满了看似相似的成员,他们以略有不同的方式完成相同的工作。
最终我们会忘记谁在使用哪种方法以及用于什么目的。没有人敢改变现有的方法,因为害怕破坏一个未知的客户。所以开发者复制了一些看起来正确的东西,让它有点不同,然后称之为别的东西。这种服务 API 污染模式对于使用过企业应用程序的任何人来说都应该很熟悉。
例外处理
每一个看似“规则”都注定要被打破。当然,有时让服务器为显示准备数据既方便又高效。这种情况最常发生在汇总数据层上甚至更大量复杂数据的大量只读数据中。当我走这条路时,我通常是出于性能考虑。否则,我会坚持面向实体的架构。
当我的应用程序中的 一切 看起来都符合异常时,我会得出结论认为我的架构对于这个特定的应用程序 是错误的......这应该不要成为微风应用程序。我不知道这是不是你的情况。
希望这会有所帮助。