1

My problem is relatively simple:

I have an entity with many lazily loaded Sets that I don't need all the time. Now I don't want to load everything eagerly, nor do I want to have several different getSlimEntity(), getFullEntity(), getEntityForSpecialOccasion() methods.

What I'd like to do is having the 'slim' version by default and then load the lazy stuff on demand. That demand could originate in changing a tab on a web page displaying a 'task' entity. The new tab should display the task's history. This tab isn't used very often, though, so I don't want the data eagerly.

A solution should put as little work as possible on the database since database performance this is a problem for us.

A possible solution I came up with is using Session.buildLockRequest() to 're-attach' the task to the EntityManager and the call Hibernate.initialize() on the Set I need. It looks like this:

public Set<HistoryEntry> getHistory(Task task) {

    Session session = manager.unwrap(Session.class);
    session.buildLockRequest(LockOptions.NONE).lock(task);

    Hibernate.initialize(task.getHistory());

    return task.getHistory();
}

It's a slim and relatively easy-to-understand solution, also the database isn't updated or anything, just queried for the HistoryEntries in question.

Now my question(s): Is this solution okay to use? Does it pose any problems I don't see? What is actually happening by calling buildLockRequest? Also, could there be problems when multiple users view the same task?

// Edit: As pointed out, this solution uses Hibernate specific calls that may not be compatible with other Persistence Providers, such as EclipseLink or OpenJPA. Since this project is internal only, that should not be a problem.

Markus Rohlof
  • 380
  • 3
  • 13
  • 2
    Your solution lacks portability as it is meant/intended by JPA. You won't be able to port your code to other environments - for instance: Application Servers - in which your customers might use other Persistence Providers, such as EclipseLink or OpenJPA. Reason: in some deployments there are no Hibernate libraries available at runtime. – MWiesner Feb 25 '16 at 08:35
  • @MWiesner Thank you for your valuable feedback, that's good to know for the future! I think this problem should not apply to this project since we are an internal IT department with full control over our deployments and do not sell our software solutions to external customers. – Markus Rohlof Feb 25 '16 at 09:08

1 Answers1

2

I am not sure if using LockRequest#lock() to reattach object to session (by the way, it behaves strangely as it does not make any version check or synchronize changes) is a good idea. In your case it may seem like a proper solution, but it just looks like a side effect and I would not rely on this feature.

The other thing is - talking about Hibernate specific calls when using JPA is bad as MWiesner already pointed out in comment.

You have so many alternatives:

  1. If you know how an object will be used at the time of retrieval from DB - make use of entity graphs.
  2. You can just make query retrieving all Histories for passed entity.
  3. If you know that the passed object cannot be changed, you can just reattach it to persistence context via EntityManager#merge.

Why don't select one of above?

Maciej Dobrowolski
  • 11,561
  • 5
  • 45
  • 67
  • 1.) To me it looks like entity graphs are only available in JPA 2.1. We are currently running JPA 2.0 and it's not in my power to change that any time soon... 2.) How would I attach the Histories to the passed entity then? Part of why I like the lockRequest-solution is that the entity then holds all its history-entries. 3.) I should try that. Not sure whether it causes additional queries, though... – Markus Rohlof Feb 25 '16 at 09:16
  • "but it just looks like a side effect and I would not rely on this feature" - I strongly agree on that. – MWiesner Feb 25 '16 at 09:27
  • @MarkusRohlof 2) that's right, attaching `Histories` to passed entity may be cumbersome, but look at that method, it returns `Set`. – Maciej Dobrowolski Feb 25 '16 at 10:09