Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading multiple entities by id efficiently in Hibernate

So, I'm getting a number of instances of a particular entity by id:

for(Integer songId:songGroup.getSongIds()) {
   session = HibernateUtil.getSession();
   Song song = (Song) session.get(Song.class,id);
   processSong(song);
}

This generates a SQL query for each id, so it occurred to me that I should do this in one, but I couldn't find a way to get multiple entities in one call except by running a query. So I wrote a query

return (List) session.createCriteria(Song.class)
       .add(Restrictions.in("id",ids)).list();

But, if I enable 2nd level caching doesn't that mean that my old method would be able to return the objects from the 2nd level cache (if they had been requested before) but my query would always go to the database.

What the correct way to do this?

like image 767
Paul Taylor Avatar asked Feb 23 '12 17:02

Paul Taylor


People also ask

How do you map multiple entities on the same table?

Entity Mappings If you want to map the same database table to two entities, you should create a simple inheritance hierarchy. The superclass should be abstract and contain all attributes that are shared by both entities. You should map it as a mapped superclass so that it is not an entity itself.

Can we have multiple ID in Hibernate?

So yes, you can have more than one @Id.

How does Hibernate fetch multiple entities by id?

You just need to call the byMultipleIds(Class entityClass) method on the Hibernate Session and provide the class of the entities you want to load as a parameter.


1 Answers

What you're asking to do here is for Hibernate to do special case handling for your Criteria, which is kind of a lot to ask.

You'll have to do it yourself, but it's not hard. Using SessionFactory.getCache(), you can get a reference to the actual storage for cached objects. Do something like the following:

for (Long id : allRequiredIds) {
  if (!sessionFactory.getCache().containsEntity(Song.class, id)) {
    idsToQueryDatabaseFor.add(id)
  } else {
    songs.add(session.get(Song.class, id));
  }
}

List<Song> fetchedSongs = session.createCriteria(Song.class).add(Restrictions.in("id",idsToQueryDatabaseFor).list();
songs.addAll(fetchedSongs);

Then the Songs from the cache get retrieved from there, and the ones that are not get pulled with a single select.

like image 103
sharakan Avatar answered Oct 11 '22 06:10

sharakan