【问题标题】:How to test whether lazy loaded JPA collection is initialized?如何测试延迟加载的JPA集合是否初始化?
【发布时间】:2011-05-17 10:16:09
【问题描述】:

我有一个从外部代码获取 JPA 实体的服务。在此服务中,我想遍历一个延迟加载的集合,该集合是该实体的一个属性,以查看客户端是否向其添加了相对于数据库中当前版本的内容。

但是,客户端可能从未接触过该集合,因此它仍未初始化。这导致了众所周知的

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.SomeEntity.

当然,如果客户从未接触过该集合,我的服务就不必检查它是否有可能发生的变化。问题是我似乎无法找到一种方法来测试集合是否已初始化。我想我可以打电话给size(),如果它抛出LazyInitializationException,我会知道,但我尽量不依赖这种模式。

在某处有一些isInitialized() 方法吗?

【问题讨论】:

    标签: java hibernate jpa lazy-loading


    【解决方案1】:

    你在使用 JPA2 吗?

    PersistenceUnitUtil 有两种方法可用于确定实体的加载状态。

    例如组织和用户之间存在双向 OneToMany/ManyToOne 关系。

    public void test() {
        EntityManager em = entityManagerFactory.createEntityManager();
        PersistenceUnitUtil unitUtil =
            em.getEntityManagerFactory().getPersistenceUnitUtil();
    
        em.getTransaction().begin();
        Organization org = em.find(Organization.class, 1);
        em.getTransaction().commit();
    
        Assert.assertTrue(unitUtil.isLoaded(org));
        // users is a field (Set of User) defined in Organization entity
        Assert.assertFalse(unitUtil.isLoaded(org, "users"));
    
        initializeCollection(org.getUsers());
        Assert.assertTrue(unitUtil.isLoaded(org, "users"));
        for(User user : org.getUsers()) {
            Assert.assertTrue(unitUtil.isLoaded(user));
            Assert.assertTrue(unitUtil.isLoaded(user.getOrganization()));
        }
    }
    
    private void initializeCollection(Collection<?> collection) {
        // works with Hibernate EM 3.6.1-SNAPSHOT
        if(collection == null) {
            return;
        }
        collection.iterator().hasNext();
    }
    

    【讨论】:

    • 你说得对,谢谢!我忘了检查堆栈溢出,很抱歉迟到了。
    • 或者更简单的使用静态方法:Persistence.getPersistenceUtil().isLoaded(org,"user")
    【解决方案2】:
    org.hibernate.Hibernate.isInitialized(..)
    

    据我所知,没有标准的 JPA 解决方案。但是如果你想真正初始化集合,你可以创建一个实用方法并对其进行迭代(只需一次迭代就足够了)。

    【讨论】:

    • 这正是我正在寻找的,谢谢!问题是,即使我碰巧使用的是 Hibernate,代码也应该是 JPA 兼容的,所以不幸的是我不能真正使用它:(
    • entityManager.find() 非常标准 ;) 换句话说,代码也应该在 EclipseLink 上工作 ;)
    • find() 不是在做不同的事情吗?
    • 是的,但我的意思是你说“没有什么是标准的”,但是发现,即使它做了其他事情,也适用于 Hibernate 和 EclipseLink。所以换句话说,“标准确实存在”。
    • 这也适用于我。虽然我发现 Hibernate 抽象非常有漏洞。我不想在我的控制器中包含像“Hibernate.xy()”这样的代码。我明白为什么不能轻易修复它,因为 Hibernate 为“无缝”工作的承诺付出了很多,这导致了这样的抽象泄漏......
    【解决方案3】:

    对于eclipselink,用户将您尝试访问的集合投射到org.eclipse.persistence.indirection.IndirectList,然后调用其isInstantiated() 方法。以下链接有更多信息:

    http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/indirection/IndirectList.html#isInstantiated.

    【讨论】:

      猜你喜欢
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 2020-01-23
      • 1970-01-01
      • 2014-06-12
      • 2016-12-21
      • 2015-11-01
      • 1970-01-01
      相关资源
      最近更新 更多