Hibernate – 避免LazyInitializationException – 从代理和会话中分离对象

MyObject myObject = repositoryHibernateImpl.getMyObjectFromDatabase(); //transaction is finished, and no, there is not an option to reopen it ThirdPartyUtility.doStuffWithMyObjectType( myObject ); 

在这一点上你已经定义了什么是懒惰和急切加载,第三方实用程序将尝试调用你的“myObject”实例上的所有方法,这很好,因为你不想为懒惰返回任何东西加载属性,遗憾的是它不返回null,它抛出一个LazyInitializationException

发生这种情况是因为您实际上是在Hibernate的对象代理上调用该方法,并且它知道它没有获取该数据,并抛出exception。

甚至可以使用null值获取底层对象,以便getter只返回null,并且不会抛出exception? 基本上分离对象,以便Hibernate完全不再了解它。 延迟加载的对象的访问器必须返回null,它不能返回实际值,我们希望能够将实体转换为POJO,而不必创建看起来像实体的对象,并且必须重新映射所有值。

假设你有一个领域,你可以在吸气器中:

 MyField getMyField() { if (Hibernate.isInitialized(myField)) { return myField; } return null; } 

从org.hibernate.Hibernate的javadoc:

public static boolean isInitialized(Object proxy):检查代理或持久集合是否已初始化。

如果您不想将域与Hibernate耦合,另一种可能性是让您的DAO从getMyObjectFromDatabase()内部实例化您自己的实体实例,并使用Hibernate代理中的相应字段填充该实例。 我做到了这一点,效果很好。

显然这是更多的代码,但如果这是您想要的,那么您可以保证实体的“纯粹”实例(完成null未初始化的值)。

检查我的解决方案

最小的例子:

我不从对象加载属性,而是从控制器加载属性。
码:

 {..} MyProp prop = employeeController.getMyProp(employee); {..} 

这将通过存储库对象初始化该属性并返回它。
EmployeeController.java:

 public Set getMyProp(Employee employee) { if (this.employeeRepository.InitMyProp(employee)){ return employee.getMyProp(); } return null; } 

存储库获取/打开会话, 重新加载员工对象 ! 并初始化延迟加载的字段
EmployeeRepository.java:

 public boolean InitMyProp(Employee employee) { if (Hibernate.isInitialized(employee.getMyProp())){ return true; } try { Session session = getSession(); session.refresh(employee); Hibernate.initialize(employee.getMyProp()); } catch (Exception ex) { return false; } return true; } private Session getSession(){ if (session == null || !session.isConnected() || !session.isOpen()){ session = HibernateUtil.getSessionFactory().getCurrentSession(); } if (!session.getTransaction().isActive()) { session.beginTransaction(); } return session; } 

我在我的解决方案中有一个带有几千条记录的TableView和另外两个TableView,其中包含第一个TableView中所选记录的详细信息。
希望能帮助到你。