AirmanAJK
AirmanAJK

Reputation: 111

Dynamic Eager & Lazy Loading in Hibernate

I'm new to Hibernate, but have plenty of experience with the Entity Framework in C#. One feature I love is the ability to dynamically decide what to load immediately in a query. For example, consider a One-to-Many relationship of Class and Student Entities.

On a "View Classes" page I can do this:

context.Configuration.EnableLazyLoading = true; //default option
List<Classes> classes = context.Classes.ToList();

Now I can happily just show the class info, without wasting resources gathering student data. ONLY when the user clicks the "View Classes with Rosters" do I do the following:

context.Configuration.EnableLazyLoading = true;
List<Classes> classes = context.Classes.Include(c => c.Students).ToList();

With that one statement, I was able to decide that in this particular situation, I want to grab all the info at once. Not two queries. Not one-hundred queries. Just one query. All despite loading only the classes a few seconds prior.

All of my reading on Hibernate explains how you can specify lazy="true|false" in the configuration files of relationships, but I really want the option of deciding when to load collections on the fly. After all, I'm not interested in buying a car that only goes either 30mph or 60mph. I need to choose a speed depending on where I am.

Perhaps the option of using fetch mode as JOIN is acceptable in that it will only be two queries in this situation (one for the class, and one for the students), but I really liked having the option of doing it all in one query, especially if I have several child collections to load and don't want to perform a query per relationship. I realize the all-at-once joins create extra data that needs to be streamed, but I'm surprised that this level of control isn't easily done or may be unavailable entirely.

Upvotes: 6

Views: 3963

Answers (2)

v.ladynev
v.ladynev

Reputation: 19976

Hibernate doesn't have very convienent ways for dynamic fetching. You can control it by

  1. Using Dynamic fetching via HQL queries with join fetch (as @ThibaultClement suggested).
  2. Using Dynamic association fetching with Criteria.setFetchMode().
  3. Using Dynamic fetching via profiles with the @FetchProfile annotation.
  4. Using Hibernate.initialize()

You can refer HQL joined query to eager fetch a large number of relationships for additional thoughts too.

Upvotes: 2

6harat
6harat

Reputation: 622

As mentioned by @v.ladynev, querydsl is a good option. However, still, there is not a clean way to handle it in my opinion.

  1. If you use .select(...) the result would be a Tuple and not the original entity (with unmentioned fields as defaulted to null) which will lead to writing some boiler-plate code for mapping it to the original entity.
  2. The other possible solution related to querydsl is using QueryProjection but again it requires you to write a separate class with different possibilities.
  3. A third solution can be to keep all joins as Fetch.LAZY and then use JpaUtils.initialize() (or hibernate's own method) to fetch the entity graph as required. (But as far as performance is concerned this would be worse than using join fetch directly which would only make 1 sql call).
  4. A different flavour of third option worth looking at is to use NamedEntityGraph or EntityGraph for fetching the required parts.

Upvotes: 0

Related Questions