views:

554

answers:

3

Is there any truly practical way to avoid using DTOs, when passing data through Hibernate-backed transactional service methods? In other words, are DTOs the only non-hacky solution to avoiding lazy initialization problems?

I think the two popular alternatives to DTOs and the reasons I don't really like them are:

  1. Open Session in View pattern. This I don't like as I would like to keep the service methods truly transactional (i.e. the Hibernate session is committed and closed when the method exits). This is mainly because I would like to not have to worry about transactions if I for example need to publish the service as a web service later on.

  2. Passing domain/business objects through service methods instead of DTOs and eager fetching the needed attributes/properties. This is somewhat better. However in a non-trivial domain object hierarchy with complicated entity relations the eager fetching has to stop somewhere. And when it does, I can't see how this wouldn't very quickly turn into a complete hackaton replacing entities with referencing ids all over the place.

Am I missing something or are DTOs in fact the only solid approach from maintainability's point of view?

A: 

If you relax your requirement to close the session, you can still use open session in view and just commit everything in your service transactions. The session will still be available to lazy fetch but all your transactions will be complete. But if you're going to switch to a web service, then you would need to eager load all of your entities anyway. DTOs just force you to consciously eager load and prevent accidental laziness.

So, bottom line, if you're careful, you can skip the DTOs in both environments, but I would probably stick with open session in view and worry about web services when they actually become a requirement.

Brian Deterling
Leaving the session open does seem sensible. The tricky part with the web services is that if the entity object tree is deep, some branches have to be cut off (to be queried later) or replaced with referencing ids. Once you do this, you basically have a DTO even if its formed outside the service.
+1  A: 

Repositories, Services, and Controllers should be the places dealing with your application core (Hibernate Session can certainly be used as the entirety of your repository layer, if you like).

Views are not supposed to be dealing with your application core, the domain model. They should not be dealing with the live objects, but with a non-live, tailored representation of the live objects. Views are supposed to be handed just the data they need, in the particular format they need it. You should build DTOs for your views. This pattern is also known as View Model, to contrast with Domain Model.

To make your life easier, there may be libraries or frameworks which can auto-map from your domain model objects to your view model objects, and back. In .NET, there is an open source framework called AutoMapper currently in development; I'm not sure what there is for Java.

Justice
I believe Dozer does auto-mapping of Java domain objects to/from DTOs, but I've never used it myself.
Andrew Swan
A: 

The only way to really use entities end to end is to use something a little bit more sophisticated than OpenSessionInView. In my experience you're going to have to manage the hibernate session manually at the application level. OpenSessionInView will only give you the same session for one request. After that you'll need to be constantly reattaching to the current session. Take a look at Seam and conversations, or implement your own Hibernate Session management. We currently manually manage our sessions based on when a wizard starts and ends and use Spring AOP to attach sessions to the right threads just in time(Sessions are not thread safe, not a good mix with AJAX)

WebServices on the other hand most certainly are going to need some form of DTO. I don't see a way around that. Entities may look like POJOs but aren't really, serializing them can range from difficult to nearly impossible. Just create DTOs that fit with the goal of the service method and be done with it.

Personally I don't think the DTO pattern is terrible, if you're just making a website it's feasible to go end to end with entities and it may even buy you some performance but if you'd like a more flexible architecture, stick with DTOs.

David Ortiz