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

时间:2010-08-17 17:56:41

标签: java hibernate lazy-loading

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

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

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

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

3 个答案:

答案 0 :(得分:2)

让我们说你有一个领域,你可以在吸气器中:

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

来自org.hibernate.Hibernate的javadoc:

  

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

答案 1 :(得分:0)

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

显然,这是更多的代码,但如果你想要的话,你可以保证你的实体的“纯粹”实例(包含null未初始化的值)。

答案 2 :(得分:0)

检查我的解决方案。

最小例子:

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

{..}

MyProp prop = employeeController.getMyProp(employee);

{..}

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

public Set<MyProp> 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中所选记录的详细信息。
希望它有所帮助。