PDA

View Full Version : Spring+Hibernate in a layered architecture


carlos
Aug 20th, 2004, 10:53 AM
Hi,

I use Hibernate and I'm having trouble with persistent objects and transactions.

In my business layer I call my DAO methods (e.g. load) that in turn call HibernateTemplate.load and return the persisted object to the business layer.
There I want use it as it were a Transfer Object, changing some of its values, but as it's done inside a transaction the object is cached in the session and every change I made to it is persisted when closing the session at the end of the transaction (are these assumptions true?)
Seems that there's no method to dettach persisted objects from the session and maybe a solution could be return a clone of the persisted object in the DAO or creating a Transfer Object with data from the persisted object.

If anyone asks about it I don't want to use the OpenSessionInView filter as it breaks the layered architecture.

And a sample can be a use case where I want to return a department with only the employees that have some attribute. I load the department object with a lazy collection of employees calling dao.load(). Then I can call dao.getEmployeesXXX that uses a filter to get only a subset of employees from the lazy collection).
To sum up:
department = dao.load(id);
department.setEmployees(dao.getEmployeesXXX(depart ment));

if department is the same object as returned by Hibernate then I'll get errors or it will be update in database with only those employees from dao.getEmployeesXXX

Thanks in advance.

irbouho
Aug 20th, 2004, 11:09 AM
With Hibernate3 you could use Filters (http://blog.hibernate.org/cgi-bin/blosxom.cgi/Steve%20Ebersole/v3-filters.html) :wink:

I think you can do the following:

//add a copy contructor to your Department class
public Department(Department department) {
//copy base properties
}

//then in your DAO
department = dao.load(id);
Department dept = new Department(department );
dept.setEmployees(dao.getEmployeesXXX(department)) ;

If you do not like the copy constructor (as in normal use, it should also copy the employees), you can copy a subset properties with d1.setXXX(d2.getXXX()) in your dao.

carlos
Aug 20th, 2004, 12:32 PM
Yes I have read something about Hibernate3, but I can't wait :cry:

The copy constructor is almost the same option as cloning, I think that's what I'll use if there's no better option, but a better approach than your implementation can be using commons-beanutils reflection methods.

I think somebody else has to have faced this problem because one of the main reasons to use ORM is not to code TOs

futang
Aug 20th, 2004, 02:52 PM
Hi Carlos,

Let me make sure about your question and then I'll give it a shot. You want to load an object (I'll use your Department/Employees examples), filter it's collections and then return it to your view. You are concerned that by filtering the collection the Employees removed by the filter will lose their association to the Department when the session is flushed (ie when the transaction commits).

If this is the case you want to mark your transaction as readOnly. When using hibernate this means the session will not be flushed. There was just recently a thread on this here,

http://forum.springframework.org/showthread.php?t=9675

Hope this is helpful,

Mike

irbouho
Aug 20th, 2004, 03:16 PM
but a better approach than your implementation can be using commons-beanutils reflection methods.

Agree, however I think making my domain object dependent on commons-beanutils would not be a good design.

carlos
Aug 21st, 2004, 06:01 AM
You are concerned that by filtering the collection the Employees removed by the filter will lose their association to the Department when the session is flushed (ie when the transaction commits).


You're right


If this is the case you want to mark your transaction as readOnly.


This is not possible some times, e.g. I want the createDepartment method to return the created object, so in that transaction I want to both update database and transform an hibernate persisted object in a TO.

wdemoss
Aug 26th, 2004, 03:18 PM
Would a session.evict(Object) accomplish what you want? It detaches the instance from the currently open session.
-wd

carlos
Aug 26th, 2004, 03:49 PM
But also prevents flushing wanted changes to database