views:

702

answers:

2

So I've got a simple web application using Spring MVC + Hibernate and am using the OpenSessionInViewFilter. I've recently been thinking of replacing the UI with something like Flex or GWT.

At first I thought it would be easy, in that I can just hit my service layer from the new front end. But as I consider this a bit more, I'm a little bit nervous about the issues surrounding lazy loading. Using a traditional web front end it's no problem because I'm using open session in view...everything that needs to get loaded for the view gets loaded as the view is constructed.

So Let's say I've got a method to return a Customer, and a Customer has a bunch of Contacts, and Contacts have a bunch of Addresses, and so on. If I call getCustomer() from my new "RIA" controller, it's going to get a Customer, but the Customer's collection of Contacts is just going to be a proxy or null.

I could create a new layer on top of what I've already got that returns DTOs which are pre-populated...but... that seems like it's going to get complicated.

Any advice?

A: 

If your presentation layer requires the presence of customer contacts, the data layer will provide it. The purpose of lazy loading is not to omit data...it's used in computer programming to defer initialization of an object until the point at which it is needed.

You need not worry.

Robert Harvey
Hmm, that doesn't quite make sense to me. The objects I'm returning will be serialized, so everything they contain will have to be loaded before they're sent off. So if I call a method getCustomer() and a Customer has a collection of, say, Contacts which is lazy loaded, the Customer object would not contain a valid collection of Contacts at the time of serialization. When the client tries to do getCustomer().getContacts(), it's not going to get anything.
Boden
Actually it looks like my concerns might be realized backwards - everything is going to get loaded at serialization (at least using spring's blazeds)...which presents a different problem all together. See the following: http://www.infoaccelerator.net/blog/post.cfm/bypassing-hibernate-s-lazy-loading-in-blazeds-with-spring
Boden
+2  A: 

You're absolutely right that this does introduce a problem for RIAs. If you're using OpenSessionInViewFilter then data won't get returned null; rather the serializer will walk the entire object graph and send an enormous amount of data back. This is going to introduce serious performance problems.

Introducing a separate DTO layer gives you a lot of control in that you can ensure that the serializer only walks objects you've constructed; you can ensure that they contain no lazy proxies. This unfortunately introduces some tedium in writing mapping code between your entities and DTOs but it does give you full control to do anything you want.

Another approach is to introduce a layer just before the serializer that prepares your object graph for serialization. One approach we used on some past projects was to introduce an aspect to the service layer that would walk the entire object graph and replace lazy proxies with a new instance of the Entity with only its @Id property set. If the graph got saved back at a later time, this would ensure that @ManyToOne relationships were not inadvertently nulled. You could call getters or use Hibernate.initialize() to force initialization of data you did want to send over the wire. This does get more complicated when you introduce cascading saving of @OneToMany or @ManyToMany relationships in Hibernate.

I recently came across a solutin called Gilead that is designed to handle this problem. It uses an approach similar to the one described above:

http://noon.gilead.free.fr/gilead/

I also believe Granite DS has a solution to this problem as part of its Tide framework:

http://www.graniteds.org/confluence/display/DOC/4.+Lazy+Initialization

One problem I don't think anyone has solved is a way to actually lazy load data in a RIA from the server. I think it could certainly be done but there are some security concerns here. You would need pretty robust security checking in place to make sure that any attempts to lazy load the data were from the user who actually has permission to load that data in the first place.

cliff.meyers
Thank you! Do you have any experience with dpHibernate? I think it may solve this problem for me but I'm not sure (that is, if I choose to use Flex).
Boden
I haven't coded with dpHibernate although I have reviewed the documentation. One of the big concerns I had was that it didn't seem to address the security questions but I may have missed something.
cliff.meyers
Can you elaborate at all on the security concerns you have?
Boden
Sure. When you create a domain model using Hibernate, just because a user has access to one Entity doesn't necessarily mean that the user should be able to navigate all the relationships on it to access all the other data. A contrived example might be a "User" class which has a @OneToMany with a "Credential" class. The documentation isn't real clear about how these relationships are navigated. Exposing a raw data access API to a RIA application could be dangerous in the same way that exposing a database directly to a thick client can be.
cliff.meyers