Farheen Patel
Farheen Patel

Reputation: 51

How to avoid Eager column to be initialized in hibernate criteria for an Entity

Multiple Entities are associated with @OnetoMany relations and Eager Loaded with an Entity. While fetching data using Hibernate criteria, the related Eager column is initialized which is causing performance issue for my project as it is huge and there are many Eager loaded relationships.

What would be the best way to avoid initialization of Eager column while using hibernate criteria to fetch data.

Upvotes: 4

Views: 3309

Answers (6)

Amit Vyas
Amit Vyas

Reputation: 790

You can explicitly define properties with criteria to be fetched in lazy mode.

criteria.setFetchMode("property_name", FetchMode.SELECT); 

In hibernate code SELECT is Lazy.

public static final FetchMode LAZY = SELECT;

Hibernate document link

https://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/querycriteria.html#querycriteria-dynamicfetching

Upvotes: 0

Jean Marois
Jean Marois

Reputation: 1630

You could use a projection. If you are using Spring Data, it includes some nice helpers see Baeldung: Spring Data JPA Projections and Spring Data JPA Reference for details. If you are using Hibernate directly, see Baeldung: JPA/Hibernate Projection and Hibernate JavaDoc Projection

Hibernate (direct quote from Baeldung)

To project on multiple columns using JPQL, we only have to add all the required columns to the select clause:

Query query = session.createQuery("select id, name, unitPrice from Product"); List resultList = query.getResultList();

But, when using a CriteriaBuilder, we'll have to do things a bit differently:

CriteriaBuilder builder = session.getCriteriaBuilder(); CriteriaQuery<Object[]> query = builder.createQuery(Object[].class); Root product = query.from(Product.class); query.multiselect(product.get("id"), product.get("name"), product.get("unitPrice")); List<Object[]> resultList = entityManager.createQuery(query).getResultList(); Here, we've used the method multiselect() instead of select(). Using this method, we can specify multiple items to be selected.

Another significant change is the use of Object[]. When we select multiple items, the query returns an object array with value for each item projected. This is the case with JPQL as well.

Let's see what the data looks like when we print it:

[1, Product Name 1, 1.40] [2, Product Name 2, 4.30] [3, Product Name 3, 14.00] [4, Product Name 4, 3.90] As we can see, the returned data is a bit cumbersome to process. But, fortunately, we can get JPA to populate this data into a custom class.

Also, we can use CriteriaBuilder.tuple() or CriteriaBuilder.construct() to get the results as a list of Tuple objects or objects of a custom class respectively.

I suggest reading the Baeldung article, it goes into more detail.

Upvotes: 1

Krishnakumar K P
Krishnakumar K P

Reputation: 36

Which JPA version are you using? JPA 2.1 has introduced Dynamic fetching via JPA entity graph Or you may probably try with Dynamic fetching via Hibernate profile

Refer https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/fetching/Fetching

https://docs.jboss.org/hibernate/orm/5.0/userguide/en-US/html/ch09.html

Upvotes: 0

Conrad
Conrad

Reputation: 564

I would suggest using fetch= FetchType.LAZY but you have to check code for transactions. If they are created then you're fine, otherwise you'll get LazyInitializationException when trying to use that data.

If you don't want it to be eagerly fetched every time you fetch parent entities there is two solutions without changing legacy code. First one is to create entity graph and including that in graph. So you would fetch data with your graph and that would be it. No more additional sql queries to fetch eager collection. Second solution is to create entity for same table but with everything marked lazy.

Upvotes: 0

Akshay Babbar
Akshay Babbar

Reputation: 11

I would also suggest the same that has been mentioned by Mayuree. In further, see if you can play below condition:

  • reduced batch size could also help there if so that the pagination helps you there.
  • it will increase the boot time but the Db performance trade-off is immense. You can eagerly load the necessary table that you require.

Source

Upvotes: 0

Mayuree Budhe
Mayuree Budhe

Reputation: 130

If you are using @OneToMany annotation then there is an attribute called fetch= FetchType.LAZY.

You can use it. It will notify hibernate for Lazy loading. For more info you can refer Baeldung.com and search for Eager and Lazy Loading

Upvotes: 0

Related Questions