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
Java 8 Date and Time: Parse Iso 8601 String Without Colon in Offset
How to Generate the JPA Entity Metamodel
In Java, When Should I Create a Checked Exception, and When Should It Be a Runtime Exception
Jackson Renames Primitive Boolean Field by Removing 'Is'
Using Internal Sun Classes with Javac
Deserializing Polymorphic Types with Jackson Based on the Presence of a Unique Property
Why Shouldn't You Extend Jframe and Other Components
Converting a Java Keystore into Pem Format
Convert from List<Completablefuture> to Completablefuture<List>
What's Up with Java's "%N" in Printf
How to Sort Date Which Is in String Format in Java
Java Regular Expression to Extract Content Within Square Brackets
How to Find Where Jdk Is Installed on My Windows MAChine
How to Get SQL from Hibernate Criteria API (*Not* for Logging)