How to Fetch Fetchtype.Lazy Associations with JPA and Hibernate in a Spring Controller

How to fetch FetchType.LAZY associations with JPA and Hibernate in a Spring Controller

You will have to make an explicit call on the lazy collection in order to initialize it (common practice is to call .size() for this purpose). In Hibernate there is a dedicated method for this (Hibernate.initialize()), but JPA has no equivalent of that. Of course you will have to make sure that the invocation is done, when the session is still available, so annotate your controller method with @Transactional. An alternative is to create an intermediate Service layer between the Controller and the Repository that could expose methods which initialize lazy collections.

Update:

Please note that the above solution is easy, but results in two distinct queries to the database (one for the user, another one for its roles). If you want to achieve better performace add the following method to your Spring Data JPA repository interface:

public interface PersonRepository extends JpaRepository<Person, Long> {

@Query("SELECT p FROM Person p JOIN FETCH p.roles WHERE p.id = (:id)")
public Person findByIdAndFetchRolesEagerly(@Param("id") Long id);

}

This method will use JPQL's fetch join clause to eagerly load the roles association in a single round-trip to the database, and will therefore mitigate the performance penalty incurred by the two distinct queries in the above solution.

Spring Data JPA load lazy associations using native query

With plain Spring Data, you are out of luck because it is simply so limited. You have to use Hibernate APIs to achieve what you want with a native query. There you can specify for a query that you want to materialize some columns for the association of an entity e.g.

List<Entity1> list = session.createNativeQuery("select {t1.*}, {t2.*} from tbl1 t1 join tbl2 t2 ...", Entity1.class)
.addEntity("t1", Entity1.class)
.addJoin("t2", "t1", "associationName")
.getResultList();

Alternatively, you can introduce a custom SQLFunction to model this PostgreSQL operator and still continue to use JPQL/HQL. See a similar answer for supporting array functions in PostgreSQL: HQL - Check if an Array contains a value

Spring Security Hibernate load user with lazy associations

You don't need to load @ManyToOne (like Todos) part of the associations at all.
Just create new TodoEntity, assign a user to it and save.

if you need to modify anything, better to work with all the user's associations separately from a user.

FetchType.LAZY in ManyToMany doesnot work

Lazy loading works as expected, as it loads all data lazy.

What you are looking for is a way to break loop in the bi-directional mapping.

There you can use @JsonManagedReference and @JsonBackReference that you have to set on the relationships.

Please also read this: https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion

Why does FetchType.LAZY not work in Hibernate/JPA?

Finally I was able to figure it out. The issue is related to kotlin data classes (see KT-28525)

One should not use data classes with spring-data-jpa. Referenced from kotlin spring-guide

Here we don’t use data classes with val properties because JPA is not designed to work with immutable classes or the methods generated automatically by data classes. If you are using other Spring Data flavor, most of them are designed to support such constructs so you should use classes like data class User(val login: String, …​) when using Spring Data MongoDB, Spring Data JDBC, etc.

In order to make lazy fetching working as expected, entities should be open. My solution:

build.gradle.kts:

plugins {
kotlin("plugin.allopen") version "1.3.61"
}

allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.Embeddable")
annotation("javax.persistence.MappedSuperclass")
}

Why does Spring MVC controller method ignore FetchType.LAZY behaviour and act like FetchType.EAGER?

How do you verify that the association is eager? Spring MVC has something enabled by default which is called "open session in view", which allows lazy loading until the request is finished. If you "check" whether data is loaded through your debugger, the debugger will invoke the toString method of PersistentBag which will initialize the lazy collection.



Related Topics



Leave a reply



Submit