Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ignore a FetchType.EAGER in a relationship

I have a problem with EAGERs relationships in a big application. Some entities in this application have EAGER associations with other entities. This become "poison" in some functionalities.

Now my team needs to optimize this functionalities, but we cannot change the fetch type to LAZY, because we would need to refactor the whole application.

So, my question: Is there a way to do a specific query ignoring the EAGERs associations in my returned entity?

Example: when a I have this entity Person, I would like to not bring the address list when I do a query to find a Person.

@Entity public class Person {    @Column   private String name;    @OneToMany(fetch=FetchType.EAGER)   private List<String> address;  }  Query query = EntityManager.createQuery("FROM Person person"); //list of person without the address list! But how??? List<Person> resultList = query.getResultList(); 

Thanks!

Updated

The only way I found is not returning the entity, returning only some fields of the entity. But I would like to find a solution that I can return the entity (in my example, the Person entity).

I'm thinking if is possible to map the same table twice in Hibernate. In this way, I can mapping the same table without the EAGER associations. This will help me in a few cases...

like image 864
Dherik Avatar asked Jul 25 '13 01:07

Dherik


People also ask

What does FetchType eager mean?

Fetch type Eager is essentially the opposite of Lazy, Eager will by default load ALL of the relationships related to a particular object loaded by Hibernate.

What is FetchType eager in JPA?

Enum FetchType. Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed.

What is FetchType?

The FetchType defines when Hibernate gets the related entities from the database, and it is one of the crucial elements for a fast persistence tier. In general, you want to fetch the entities you use in your business tier as efficiently as possible.


2 Answers

Update (09/06/2020):

The issue was resolved on the 5.4.11 version. I can't test right now, but is expected that the JPA entity-graphs attributes not included in the graph should stay unloaded, even if they are declared EAGER.

Original answer

After all this years, override the EAGER mapping is not yet possible on Hibernate. From the latest Hibernate documentation (5.3.10.Final):

Although the JPA standard specifies that you can override an EAGER fetching association at runtime using the javax.persistence.fetchgraph hint, currently, Hibernate does not implement this feature, so EAGER associations cannot be fetched lazily. For more info, check out the HHH-8776 Jira issue.

When executing a JPQL query, if an EAGER association is omitted, Hibernate will issue a secondary select for every association needed to be fetched eagerly, which can lead dto N+1 query issues.

For this reason, it’s better to use LAZY associations, and only fetch them eagerly on a per-query basis.

And:

The EAGER fetching strategy cannot be overwritten on a per query basis, so the association is always going to be retrieved even if you don’t need it. More, if you forget to JOIN FETCH an EAGER association in a JPQL query, Hibernate will initialize it with a secondary statement, which in turn can lead to N+1 query issues.

like image 32
Dherik Avatar answered Oct 02 '22 07:10

Dherik


If you are using JPA 2.1 (Hibernate 4.3+) you can achieve what you want with @NamedEntityGraph.

Basically, you would annotate your entity like this:

@Entity @NamedEntityGraph(name = "Persons.noAddress") public class Person {    @Column   private String name;    @OneToMany(fetch=FetchType.EAGER)   private List<String> address;  } 

And then use the hints to fetch Person without address, like this:

EntityGraph graph = this.em.getEntityGraph("Persons.noAddress");  Map hints = new HashMap(); hints.put("javax.persistence.fetchgraph", graph);  return this.em.findAll(Person.class, hints); 

More on the subject can be found here.

When you use the fetch graph only fields that you have put inside @NamedEntityGraph will be fetched eagerly.

All your existing queries that are executed without the hint will remain the same.

like image 193
Milan Avatar answered Oct 02 '22 06:10

Milan