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