之前我使用过RIA服务,现在正在测试Breeze Sharp。
RIA以及Breeze给人的印象是,您在服务器/中间层看到的内容就是您在客户端上看到的内容。为了支持这一点,术语Entity正在客户端和服务器上使用。它真的是一个实体,还是它真的是客户端上的表示模型或模型?
对于具有一个或两个级别实体图的较小系统,可能没有错误认为客户端和服务器是相同的。对于图表深入五到六个级别的大型系统,需要将实体转换为DTO以使其变得简单。除非UI具有一些实体的CRUD屏幕,否则大型应用程序最终会有更多的DTO和更少的实体。大多数情况下,这些DTO将代表用户界面所需的内容,并且等同于演示模型。
为什么我们不能将客户端处理的内容视为表示模型而不是实体?
答案 0 :(得分:15)
您可以随意调用客户端实体类: - )
更严重的是,让我们了解这是一种反模式的典型推理。
我想对此非常清楚。 Breeze专为丰富的Web客户端应用程序而设计。 Breeze客户端不是表示层;它有表示层。它还有自己的业务模型和数据访问层。
条款"实体"和" DTO"对不同的人意味着不同的东西。我喜欢Evan's DDD definition for" entity"和Fowler's definition for "DTO"中的PoEAA。
Breeze客户端实体有资格成为Evans实体:" 具有贯穿时间和不同表示的不同身份的对象。您还会听到这些被称为“' " [Fowler]。微风实体不仅仅是财产袋;他们也有业务逻辑,你可以用自己的更多来扩展它们。
Breeze实体不是"演示模型" 。它们独立于任何特定的UI表示,通常不实现表示问题。
设计为可以直接绑定到可视控件。这是一个微风生产力设计决策......关于我们如何实施实体的决定。有些人 - 认为实体属性是反模式的人 - 会讨厌这种情况。埃文斯对这个问题保持沉默。 Fowler poo-poos it。如果它冒犯了你,你可能不喜欢Breeze。继续前进。
我即将辩称这是一种错误的二分法。
人们经常说" 它是通过网络发送实体的反模式。始终发送DTO "。这个措辞不力的法令背后有充分的理由。当客户端和服务器实体类相同时,您已将服务器的实现与客户端的实现相结合。如果模型在服务器上发生更改,则必须在客户端上进行更改,反之亦然,即使更改仅与其中一个层相关。这可能会影响您独立发展服务器和客户端代码的能力。我们可以接受这种耦合是为了方便(和权宜之计!),但没有人想要它。
Breeze 客户端实体类不必相同,既不是形状也不是业务逻辑,作为服务器实体类。当您在Breeze中查询时,您将 实体数据 放在网络上并将其转换为客户端实体;保存时,将客户端实体数据放在线路上,并将其在服务器上转换为服务器实体。 DTO可能涉及任一方向。重要的事实是课程可能不同。
当然,它们在概念上是相关的。如果Customer
实体的含义在双方都有很大差异,那么你就会有时间转换两个表示之间的数据。无论是否有明确的DTO,都是如此。
我们也承认,当类实际上相同时,更容易在两个方向上转换数据。如果它们不同,您需要支付映射税,并且您可能无法在客户端上编写Breeze LINQ查询。如果您愿意,您可以缴纳税款。微风并不在意。
我倾向于从双方的同一课程开始,并在必要时进行更改。这对于RIA Services和DevForce中的高比例课程来说效果很好。最重要的是,当需要出现时,我很难重新考虑分类。
< rant> 忧虑分子夸大了共享类定义的风险,并低估了映射层的成本,这些层的优势在应用程序的生命周期中很少实现。< /咆哮> 强>
您写道:
对于图表深入五到六个级别的大型系统,需要将实体转换为DTO以使其变得简单。 ......大多数情况下,这些DTO将代表用户界面所需的内容,并且等同于演示模型
根据我的经验,只有当您假设客户只是将实体粘贴到屏幕上时才会这样。但我已经规定客户端是一个应用程序,而不是表示层。
我进一步争辩说,您需要在客户端上使用域模型,原因与您在服务器上需要一个域模型相同:来推理域。您可以独立于演示文稿执行此操作。我假设您的实体将以多种方式出现在多个屏幕上,但会有不同的演示规则。它是同一个模型,提出了很多方法。我们称之为" 围绕数据"。
无论您在模型上放置多少面,基础模型数据和管理它们的业务规则应保持不变。这是什么使它成为"域模型"而不是"演示模型。"
FWIW,我总是有一个"演示模型" (AKA" ViewModel")在我的应用程序中编排View的活动。所以我不会问自己" PM或模特?"。相反,我选择 将数据直接绑定到我通过VM的api 或公开的模型实体,我将它们绑定到中间体"物品展示模型" (AKA"项目ViewModel")包装一些实体。我走哪条路是申请决定。在实践中,我首先直接绑定到实体并重构为" Item ViewModel"什么时候需要。
在任何一种情况下,我都会在客户端上构建我需要的PM(VM)。如果我需要一个" Item ViewModel",我也会在客户端上创建它。 我不会要求我的服务器为我的客户端准备DTO。对我来说这是一种反模式,因为它将服务器连接到客户端。
如何?如果开发人员需要更改客户端上的屏幕,则可能必须等待某人提供支持服务器端点和DTO。现在我们必须协调服务器和客户端的发布计划,即使更改的动力是客户端要求,而不是服务器要求。
实际上比这更糟糕。一些服务器端开发人员必须停止她正在做的事情并添加新的服务方法以满足客户需求。这不是她的要求之一......但现在就是这样。随着时间的推移,服务API大大扩展,很快它就会充斥着看似类似的成员,这些成员的工作方式略有不同。
最终我们忘记了谁在使用哪种方法和什么方法。没有人敢改变现有的方法,因为害怕打破一个未知的客户。所以开发人员复制一些看起来正确的东西,使它有点不同,并称之为其他东西。对于使用过企业应用程序的任何人来说,这种服务API污染模式应该是熟悉的。
每一个看似"规则"意味着被打破。当然,有时让服务器准备显示数据既方便又有效。这种情况最常发生在高容量,只读数据上,这些数据总结了数据层上甚至更大的复杂数据量。当我走这条路时,我通常会受到性能方面的考虑。否则,我坚持面向实体的架构。
当我的应用中的一切看起来符合异常时,我得出的结论是,我为这个特定的应用程序得到了错误的架构 ......这不应该是一个Breeze应用程序。我不知道这是不是你的情况。
希望这有帮助。
答案 1 :(得分:0)
我不知道我是否喜欢在客户端上拥有另一个域模型的想法。这将导致我们多年来一直在努力解决的传奇问题,即将业务逻辑分发给客户端。我的意思是像Windows Forms或XAML应用程序或HTML5这样的前端,只要应用程序连接到服务器。如果实体仅存在于服务器的域层中,并且被应用程序服务屏蔽,那么它是否可维护?
据我从DDD教科书中了解,当模型是一个实体时,它具有行为和数据。表示模型仅关注服务器上存在的域实体的表示。这些模型有验证。这可以很简单,因为业务规则验证需要电子邮件。当客户端处理复杂的业务规则验证时,它可能使用在域层中实现的相同规则。像RIA这样的框架的优点是可以将这些业务规则共享给客户端,因此可以避免重复。这也将强制将相同的实体推送到客户端。
我赞成客户端和服务器模型单独增长的想法 - 在服务器上的客户端和域实体上建模。所涉及的成本是模型的翻译,印迹应用服务,往返以验证业务规则是否复杂。你在答案中提到了其中一些。