2011-09-27 104 views
1

我有休眠pojo class A {B b;一些其他的适当性}对于B类,lazy = true。 当我得到对象A时,B没有被加载,并且hibernate返回它的代理。当我将这个对象传递给另一个模块时,该模块遍历A中的每个对象,当它遇到B.getXXX时,它会抛出LazyInitialization异常。在这种特殊情况下,我不想加载B类,因为它不是必需的。有没有什么办法,当我调用B方法时,它会返回null或将B的代理转换为实际对象B,以便模块不会引发LazyInitialization错误。我不能改变B类的getter,setter作为普通的类并且被其他类使用。从休眠会话中删除对象

回答

0

感谢您的所有建议。 我的应用程序有分层架构。服务 - >管理器 - >道。经理之后Hibernate会话关闭。其他模块只能通过服务进行交互。打开休眠会话,直到请求完成不是我的选择。我也不想打数据库,因为B的属性没有必要填充。我只想用真实对象替换Hibernate代理,以便任何使用服务的人都不会遇到任何问题。我在 http://svn.rhq-project.org/repos/rhq/branches/HEIKO-EXP/modules/enterprise/server/safe-invoker/src/main/java/org/rhq/enterprise/server/util/HibernateDetachUtility.java 找到一个实用程序,它正是我想要的。它检查对象并用真实对象替换Hibernate代理。我需要在上述实用程序中自定义以下内容 1.将org.rhq中的classname实例更改为我的包结构。 2.他们期望pojo身份字段的名称是“id”。我将其更改为使用具有javax.persistence.Id注释的那些属性。

基本测试与上述更改已完成,它工作正常。我只需要在各种情况下测试整个应用程序,以便它可以在所有情况下工作。

1

如果我理解你的问题,你正在检索一个对象A与B有懒关联。但是,这个关联没有被初始化,并且你发现其他模块抛出了异常,因为实际上使用了B。所以它在某种程度上需要

你想要么

  • 返回null从到B电话(不可能的,因为据我所知,除非有这些模块的一些应用程序特定的行为,只有你可以知道)或

  • 当这样的呼叫发生时初始化B。我会尽力帮助你实现这一个。

为什么你得到LazyInitializationExceptions的原因是,该获取B(并没有初始化)会议已经关闭,所以在这一点上,B实例是没有用的,在所有。您可以在此应用的一种解决方法是使用OSIV pattern,以便在所有请求范围中打开相同的Hibernate会话。这是将会获取A与懒惰B将会初始化B当需要会话。 (如果这些异常都在另一个事务的情况下发生的唯一有效的,那就是,与另一个Hibernate会话,从获取A的一个不同)

你可以申请另一种选择是在另一个会话初始化B。例如:

session.update(a.getB()); 

当然,你总是可以强制B初始化与fetchMode.EAGERHibernate.initialize(a.getB())。但是,无条件地加载实例,即使它根本不会被使用。

此外,你可以找到这个问题的答案可能是有用的:hibernate: LazyInitializationException: could not initialize proxy

0

其实,你有几个选项。

1)使A-> B关系EAGER。

2)当您尝试在休眠会话已关闭时尝试启动代理时,您会收到LazyInitializationExceptions。所以他可能的解决方案是保持Session打开,直到所有的A,B,C ...等对象操作都没有完成。

3)如果您对WEB环境感兴趣,有一种称为Open Session的模式。这会使您的Hibernate会话保持打开状态,直到HTTP请求处于活动状态。你可以阅读更多关于here。我认为这对您阅读会很有帮助。

0

当会话关闭时,不要将实体发送到其他模块。

如果这些其他模块在与会话相同的应用程序域中执行,请在调用模块时保持会话打开,并在返回时关闭它。

如果这些模块不在同一个AppDomain中,如果您需要某种序列化来发送对象,或者如果它是异步调用的,我会使用DTO。暴露服务器之外的实体(我不知道这是否是这种情况)是一个不好的做法,原因有几个。 Ayende Rahien称之为Stripper Pattern

+0

我同意将域名暴露给外界不是很好的做法。不幸的是,它是旧代码,我不能更改方法签名来使用DTO而不是域。在我的应用程序中,约有98%使用DTO,但导致问题的地方很少。 – dmay