JPA Hibernate Lazy many-to-one fetch proxy

kwisatz picture kwisatz · Mar 31, 2015 · Viewed 10.5k times · Source

I'm using JPA 2.1 and Hibernate 4.3.7

I tried to tuned my app so I turn relationships to lazy and fetch only what I need them

I have a problem with the many-to-one relationships, when turn to lazy when I load the entity again Hibernate replace the entity by a proxy even if I fetch the entity and this proxy is not working in the view part (JSF) of the application. The problem disapear when the many-to-one is in eager mode but hibernate perform one select more for each many-to-one even if I don't need them

@Entity
public class Department {
    @Id
    private Integer id;

    //...
}

1/

@Entity
public class Employee {
    @Id
    private Integer id;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "id_department", referencedColumnName = "id")
    private Department department;

    //...
}

the JPQL query:

SELECT e FROM Employee e LEFT JOIN FETCH e.department WHERE e.id=:id

=> one select query => faster but department is of type Department_$$_jvst3ac_5f (employee.getDepartment().getClass().getCanonicalName()) and this proxy doesn't work in the view part of the application

2/

@Entity
public class Employee {
    @Id
    private Integer id;

    @ManyToOne(fetch = FetchType.EAGER, optional = true)
    @JoinColumn(name = "id_department", referencedColumnName = "id")
    private Department department;

    //...
}

the JPQL query:

SELECT e FROM Employee e WHERE e.id=:id

=> two selects => slower but department is loaded as Department and everything goes fine in the view part of the application

The relation is unidirectional, Department have no references of emplyees

Is this possible to have the department without proxy when using FETCH JOIN?


After the response of Luiggi I will precised that the data are fetched with lazy many-to-one + fetch join. When I do a employee.getDepartment().toString() I have Department{ id=11, ...} but the class of this department is still Department_$$_jvst3ac_5f. For reason I don't know, the JSF/PrimeFaces selectOneMenu component don't work properly whith HibernateProxy even if the data are fetched

I tried to use the Hibernate annotation @LazyToOne(LazyToOneOption.FALSE) in addition of @ManyToOne(fetch = FetchType.LAZY) but the result is similar of @ManyToOne(fetch = FetchType.EAGER) alone...

Answer

Luiggi Mendoza picture Luiggi Mendoza · Mar 31, 2015

The problem is that when you use lazy loading you will obtain a proxy of the class (as you already stated) and this proxy can fetch the data from database only if the hibernatesession is still open. Seems like your session is being closed when returning the data to the view, so when trying to use the lazily-loaded field in the view you're getting the exception.

Possible solutions:

  • Keep the field as fetch eager and pay the overhead for each query against your entity (probably this isn't good and can affect performance, but is a solution).
  • Maintain your field as lazy and use the proper get method before the Hibernate session is closed in order to the proxy to retrieve the relevant data to be used after the session is closed.