4

在通过 Hibernate 支持的事务服务方法传递数据时,是否有任何真正实用的方法可以避免使用 DTO?换句话说,DTO 是避免延迟初始化问题的唯一非 hacky 解决方案吗?

我认为 DTO 的两种流行替代方案以及我不太喜欢它们的原因是:

  1. 在视图模式中打开会话。这是我不喜欢的,因为我想让服务方法真正具有事务性(即,当方法退出时,Hibernate 会话被提交并关闭)。这主要是因为如果我以后需要将服务发布为 Web 服务,我不想担心事务。

  2. 通过服务方法而不是 DTO 传递域/业务对象,并急切地获取所需的属性/属性。这要好一些。然而,在具有复杂实体关系的非平凡领域对象层次结构中,急切的获取必须在某处停止。当它发生时,我看不出这不会很快变成一个完整的hackaton,用整个地方的引用ID替换实体。

从可维护性的角度来看,我是否遗漏了什么或者 DTO 实际上是唯一可靠的方法?

4

4 回答 4

1

存储库、服务和控制器应该是处理应用程序核心的地方(如果您愿意,Hibernate Session 当然可以用作整个存储库层)。

视图不应该处理您的应用程序核心,即域模型。他们不应该处理活动对象,而是处理活动对象的非活动、定制表示。视图应该只以他们需要的特定格式传递他们需要的数据。您应该为您的视图构建 DTO。这种模式也被称为视图模型,与领域模型形成对比。

为了让您的生活更轻松,可能有一些库或框架可以从您的域模型对象自动映射到您的视图模型对象,然后再返回。在 .NET 中,目前正在开发一个名为 AutoMapper 的开源框架;我不确定Java有什么。

于 2009-04-15T11:05:14.063 回答
1

真正端到端使用实体的唯一方法是使用比 OpenSessionInView 更复杂的东西。根据我的经验,您将不得不在应用程序级别手动管理休眠会话。OpenSessionInView 只会为一个请求提供相同的会话。之后,您需要不断地重新连接到当前会话。看看 Seam 和对话,或者实现你自己的 Hibernate Session 管理。我们目前根据向导的开始和结束时间手动管理会话,并使用 Spring AOP 将会话及时附加到正确的线程(会话不是线程安全的,不能很好地与 AJAX 混合)

另一方面,WebServices 肯定需要某种形式的 DTO。我看不出有什么办法。实体可能看起来像 POJO,但实际上并非如此,序列化它们的范围从困难到几乎不可能。只需创建符合服务方法目标的 DTO 并完成它。

就我个人而言,我不认为 DTO 模式很糟糕,如果您只是在制作一个网站,那么与实体进行端到端是可行的,它甚至可以为您带来一些性能,但如果您想要更灵活的架构,请坚持DTO。

于 2009-04-15T14:45:58.557 回答
0

如果您放宽关闭会话的要求,您仍然可以在视图中使用打开的会话,只需提交服务事务中的所有内容。该会话仍可用于延迟获取,但您的所有事务都将完成。但是,如果您要切换到 Web 服务,那么无论如何您都需要预先加载所有实体。DTO 只是迫使您有意识地急切加载并防止意外懒惰。

因此,最重要的是,如果您小心,您可以在两种环境中跳过 DTO,但我可能会坚持使用开放会话,并在 Web 服务真正成为要求时担心它们。

于 2009-04-15T10:56:35.550 回答
0

我喜欢 DTO 的想法,但我一直觉得它们并没有被其他开发人员很好地接受或喜欢,因为正确地实现这种方法一直到数据库通常需要付出很多努力。这就是我创建Blaze-Persistence 实体视图的原因,它允许您将 DTO 建模为以有效方式映射到 JPA 实体模型的接口。您可以将实体视图应用于查询,并且查询将以仅获取实际需要的状态的方式进行调整,而不是获取所有状态并在 Java 中映射。

通过使用实体视图,您不需要在视图反模式中打开会话,因为所需的结构已被急切地加载。由于不涉及实体对象,因此也不会出现延迟加载问题。

由于实体模型在早期开发阶段通常与 DTO 模型非常相似,因此我经常看到开发人员只是跳过创建单独的 DTO 模型,因为他们试图避免麻烦。一旦实体模型中出现审计、统计或非规范化等横切关注点,或者实体模型中的数据量比实体用例实际需要的数据量大得多,开发人员就会遇到问题。

你肯定会喜欢我前段时间写的关于这件事的博客文章。

于 2018-07-19T16:49:07.917 回答