4

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.

AirmanAJK
  • 91
  • 1
  • 6

2 Answers2

1

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.

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

Community
  • 1
  • 1
v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • Fair enough. I wanted to be sure I wasn't overlooking something obvious, especially since Hibernate has various ways of gathering data. I just have to get out of the "Entity Framework Mindset" and realize different ORMs will not have a 1-1 correspondence of features. – AirmanAJK Jan 26 '16 at 17:33
  • @AirmanAJK May be, It will be interesting for you to take a look on [Querydsl](http://www.querydsl.com/), if you don't do it yet. – v.ladynev Jan 26 '16 at 18:37
0

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.
6harat
  • 542
  • 6
  • 18