Adam Bien's Weblog

Lazy Loading Entities In Views Challenge--Reader's Question And Answer

Question:

"…if I have a method in a service bean implementation:
 
public List<User> getAllUsers();

and User.java is an entity class with something along the lines of:

 class User {
   List<Address> addresses;  // Lazy loaded
   List<Friend> friends;     // Lazy loaded 
}

Then in a controller, you do getAllUsers() and render the jsp/jsf where you intend to loop through all users and for each user, you write out all addresses as an example.

The problem is that since the addresses are lazily loaded, there is no good way to actually loop through and output the addresses since we are in a detached mode already in the controller, unless you add a method getAllUserWithAddresses() or make it eagerly loaded. Then one would need one for friends as well. It gets ugly pretty quickly.

Answer:

  1. If everything is needed in the UI--why not to eager load the relations?
  2. With JXPath relations could be easily loaded just by passing a String
  3. Open Session In View Pattern / Anti-Pattern
  4. Use Stateful Session Beans with "Extended" Entity Manager
  5. Use Fetch Joins they are designed to prefetch lazy relations

Most of the items above rely on stateful architecture, what may cause some discussion about scalability.

[See also an in-depth discussion in the "Real World Java EE Patterns--Rethinking Best Practices" book (Second Iteration, "Green Book"), page 48 in, chapter "The Extended Mode"]

See you at Java EE Workshops at MUC Airport (March 25th-28th)!


NEW workshop: Microservices with Java EE 7 and Java 8, January 26th, 2015, Airport Munich

A book about rethinking Java EE Patterns

Comments:

On

1. Everything is not needed in the UI, only addresses. Friends might be needed in a totally different view.

2. Not really optimal and not too pretty using Strings. What happens when detail method is renamed?

3. Looks complicated using filters.

4. Definitely my favourite, if I understands this right. With extended, does one simple refer to user.getAddress() in the view and it gets loaded?
Should be default in JEE but with read only access. Is it possible to write from the view using extended now?

5. Yeah, not too pretty solution. Requires special methods or parameters to adjust the query.

Thanks. Number four is the bomb. Is is possible to apply this technique by defining it once as default behaviour, rather than adding it to each EntityManager?

Posted by Mohamed on December 06, 2012 at 05:25 PM CET #

You can still return DTOs from your service and fetch everything needed from within the session (I prefer fetch joins here). Instead of creating a method for every variant (getUserWithFriends, getUserWithWife, getUserWithDetail, getUserWithWifeAndDetail, ...) and thus cluttering your api with UI details, go all or nothing (getUser, getWholeUser) and optimize only as needed.

I bet you can build something nice which wraps your services and fetches automagically (interceptors, anyone?).

JXPath seems nice but may be a pain in the a** when refactoring fields or getters.

Posted by atamanroman on December 06, 2012 at 07:12 PM CET #

1. If everything is needed in the UI--why not to eager load the relations?

It is not possible to eager load more than one list in an entity. you would have to use Set instead. In my experiences that is not the best way to go.

Better is a separate service call to fetch the addresses in one query by passing the User as argument.

Posted by Markus on January 05, 2013 at 06:23 PM CET #

Markus, how can this be done in the view? You will loop through the users in the view, are you suggesting to loop through them in the controller first as well? Generate the view portion in the controller while looping? Not so nice... calling the service from the view is not allowed I believe, plus...

The point I was making was, JEE is flawed in its design. We should be allowed to request an attached entity on a need basis, a read only ... when calling a service from the controller..

myService.keepAttached().getAllUsers(...) or be able to define it globally somehow...

More flexibility from JEE on this front.

If instead of all these workarounds, the view allowed for read access to the business layer, the view layer could be much more neatly organized and structured.

Posted by Markus on February 04, 2013 at 07:02 PM CET #

You could use a @RequestScoped EntityManager (resource_local) or UserTransaction (jta) with DeltaSpike @Transactional. The entitymanager-per-request pattern works really great with JSF and JSP apps!

Of course, if your app is already fully EJB based and you only use that entity on this very page then I agree that it might be easier to just use eager loading or touch the lists in the EJB.

Posted by struberg on February 13, 2013 at 12:30 AM CET #

@Struberg,

agreed: if you build an application for an Java EE application server with the availability of CDI, JSF and JPA, but NOT EJB, you have to manually control your transactions own.

EJBs simplify transactions dramatically-> only a single annotation is needed...

Thanks!,

adam

Posted by Adam Bien on February 13, 2013 at 09:28 AM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
realworldpatterns.com
...the last 150 posts
...the last 10 comments
License