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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4306463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:41:16  来源:igfitidea点击:

How to test whether lazy loaded JPA collection is initialized?

javahibernatejpalazy-loading

提问by akira

I have a service that gets a JPA entity from outside code. In this service I would like to iterate over a lazily loaded collection that is an attribute of this entity to see if the client has added something to it relative to the current version in the DB.

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

However, the client may have never touched the collection so it's still not initialized. This results in the well known

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

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

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

Of course, if the client never touched the collection, my service doesn't have to check it for possible changes. The thing is that I can't seem to find a way to test whether the collection is initialized or not. I guess I could call size()on it and if it throws LazyInitializationExceptionI would know, but I'm trying not to depend on such patterns.

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

Is there some isInitialized()method somewhere?

isInitialized()什么方法吗?

采纳答案by dira

Are you using JPA2?

您使用的是 JPA2 吗?

PersistenceUnitUtilhas two methods that can be used to determine the load state of an entity.

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

e.g. there is a bidirectional OneToMany/ManyToOne relationship between Organization and User.

例如,组织和用户之间存在双向的一对多/多对一关系。

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();
}

回答by Bozho

org.hibernate.Hibernate.isInitialized(..)

There is no standard JPA solution to my knowledge. But if you want to actually initialize collections, you can create an utility method and iterate them (only one iteration is enough).

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

回答by robertgoko

As the other poster indicates, Hibernate has a method for this. However, there is no solution for this in pure JPA.

正如另一张海报所示,Hibernate 有一个方法。但是,在纯 JPA 中没有解决方案。

回答by amax

For eclipselink, users cast the collection you are trying to access to an org.eclipse.persistence.indirection.IndirectList, and then call its isInstantiated()method. The following link has more information:

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

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

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