数据传输对象和事务服务方法

时间:2009-04-15 08:18:03

标签: hibernate transactions lazy-loading dto data-transfer-objects

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

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

  1. 在View模式中打开会话。我不喜欢这样,因为我希望保持服务方法真正的事务性(即Hibernate会话在方法退出时提交并关闭)。这主要是因为如果我需要稍后将服务发布为Web服务,我不必担心交易。

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

  3. 从可维护性的角度来看,我是否遗漏了某些东西或DTO实际上是唯一可靠的方法?

4 个答案:

答案 0 :(得分:1)

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

视图不应该处理您的应用程序核心,即域模型。它们不应该处理活动对象,而应该使用非活动的,定制的活动对象表示。视图应该以他们需要的特定格式提供他们需要的数据。您应该为您的视图构建DTO。此模式也称为视图模型,与域模型形成对比。

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

答案 1 :(得分:1)

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

另一方面,Web服务肯定需要某种形式的DTO。我没有看到解决方法。实体可能看起来像POJO但不是真的,序列化可能从困难到几乎不可能。只需创建符合服务方法目标的DTO,并完成它。

就我个人而言,我认为DTO模式并不可怕,如果您只是建立一个网站,可以与实体端到端,甚至可能会给您带来一些性能,但如果您想要一个更灵活的架构,坚持使用DTO。

答案 2 :(得分:0)

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

所以,最重要的是,如果你小心,你可以跳过两个环境中的DTO,但我可能会坚持使用开放会话,并在实际成为要求时担心Web服务。

答案 3 :(得分:0)

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

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

由于实体模型在早期开发阶段通常与DTO模型非常相似,因此我经常看到开发人员在试图避免麻烦时只是跳过创建单独的DTO模型。一旦诸如审计,统计信息或非规范化之类的交叉问题落在实体模型中,或者实体模型中的数据量大大超过您对实体用例的实际需求,开发人员就会遇到麻烦。

对于我前一段时间写的这件事,您肯定会像blog post一样。