如何测试延迟加载的 JPA 集合是否已初始化?

60

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

但是,如果客户端从未触及过该集合,则它仍未初始化。这会导致众所周知的

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

当然,如果客户端从未触及该集合,则我的服务不必检查其中可能的更改。问题在于,我似乎找不到一种测试集合是否被初始化的方法。我想我可以调用size()并且如果它抛出LazyInitializationException,那么我就知道了,但是我试图不依赖这样的模式。

是否有某个isInitialized()方法可用?

3个回答

64
你是否在使用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();
}

1
你说得对,谢谢!我忘记回来查看 Stack Overflow 了,非常抱歉晚批准。 - akira
或者更简单地使用静态方法:Persistence.getPersistenceUtil().isLoaded(org,"user") - A. Parolini

36
org.hibernate.Hibernate.isInitialized(..)

据我所知,目前没有标准的JPA解决方案。但是如果您想实际初始化集合,可以创建一个实用方法并对它们进行迭代(仅需一次迭代)。


1
这正是我正在寻找的,谢谢!问题在于,尽管我碰巧使用了Hibernate,但代码应该符合JPA规范,所以不幸的是我无法使用它 :( - akira
entityManager.find() 是相当标准的 ;) 换句话说,这段代码也应该在 EclipseLink 上运行 ;) - akira
find() 不是做了不同的事情吗? - Bozho
是的,但我的意思是你说“没有标准”,但是find命令虽然执行其他操作,但在Hibernate和EclipseLink上都能正常工作。因此换句话说,“标准确实存在”。 - akira
1
这对我也行得通。尽管我发现Hibernate的抽象非常泄漏。我不想在我的控制器代码中编写类似于'Hibernate.xy()'这样的代码。我知道为什么不能轻易地修复它,因为Hibernate为了承诺“无缝”工作而进行了大量交易,这导致了这种抽象泄漏…… - Ondrej Burkert
但是如果你想要实际初始化集合,可以创建一个实用方法并迭代它们。这至少对于Hibernate而言是错误的。实际上,如果您在已分离的已初始化集合上执行此操作,您将会得到“LazyInitializationException:failed to lazily initialize a collection”异常。解释:延迟初始化的集合不是List或Set,而是Hibernate PersistentCollection或PersistentBag。这个东西必须有关联的session,并且在持久化上下文中被引用,否则初始化将不会执行。 - Aldian

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接