JPA and Hibernate proxy behavior

南楼画角 提交于 2019-12-03 16:38:57
kostja

This is the expected JPA behaviour. There is no reason for the entity from your query to be proxied - it is a regular result of a query. The boss property of this entity however should be a proxy. It will not tell if asked though - when you execute any operations on the lazily loaded property of a managed entity, it will trigger the fetch.

So you should access the boss property outside the transaction. If it has not been fetched, you will get a LazyInitializationException.

How you would go about it depends on the kind of the EntityManager and PersistenceContext.

  • works only since JPA 2.0 - call em.detach(loadedEmployee) and then access the boss property.

For JPA 1:

  • If you are in a Java EE environment, mark the method with @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) to suspend the transaction.

  • In an SE environment with user transactions, call transaction.commit() before accessing the boss property.

  • If using an EXTENDED PersistenceContext that will outlive the transaction, call em.clear().

EIDT: I suppose that the reason you are not getting the exception is that FetchType.LAZY is just a hint for the JPA provider, so there is no guarantee for the property to be loaded lazily. Contrary to that, FetchType.EAGER guarantees eager fetching. I suppose, your JPA provider chooses to load eagerly.

I have reproduced the example, though a bit differently and I am reproducibly getting the LazyInitializationException on the log statement. The test is an Arquillian test running on JBoss 7.1.1 with JPA 2.0 over Hibernate 4.0.1:

@RunWith(Arquillian.class)
public class CircularEmployeeTest {
    @Deployment
    public static Archive<?> createTestArchive() {
        return ShrinkWrap
                .create(WebArchive.class, "test.war")
                .addClasses(Employee.class, Resources.class)
                .addAsResource("META-INF/persistence.xml",
                        "META-INF/persistence.xml")
                .addAsResource("testSeeds/2CircularEmployees.sql", "import.sql")
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @PersistenceContext
    EntityManager em;

    @Inject
    UserTransaction tx;

    @Inject
    Logger log;

    @Test
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void testConfirmLazyLoading() throws Exception {
        String query = "SELECT e FROM Employee e WHERE e.id = 1";

        tx.begin();
        Employee employee = em.createQuery(query,
                Employee.class).getSingleResult();
        tx.commit();
        log.info("retrieving the boss: {}", employee.getBoss());
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!