I have a few simplistic use case that we are prototyping to get familiar with Spring and Hibernate processes for use in an enterprise application. I have been running into some hard to understand issues and was hoping to get some help from folks that have more experience in this than me.
Here is some information about my application:
I have a basic pojo with a single child object which is eagerly loaded. The repository for this pojo implements the basic CRUD apis using the spring HibernateDaoSupport and HibernateTemplate classes. Note, the repository implements create/update via a single "save" method that calls the "getHibernateTemplate().saveOrUpdate()" api.
My service/facades are wrapped in a transactionManager support (I finally got this to work). The service API for create/update has some additional logic that requires me to read back a list of pojos based on a key (the list will include the pojo that I have updated in the case of an update usecase) and after some validation checks saves the pojo. Now, this is where my problem starts.
My service API looks something as follows:
public CreatePojoResult createFreePeriod(Pojo pojoInstance)
{
int nUser;
// get list of Pojos for user
_repository.getPojosForUser(nUser);
// Run my validation checks << omitted here >>
// save my Pojo
_repository.save(pojoInstance);
// create and return the result object. << omitted here >>
}
When I call the createFreePeriod() API above from my facade for my insert use-case, everything works fine. However, when I call it for my update use-case, I get the following error.
org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [Pojo#1455148::1]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [Pojo#1455148::1]
org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:661)
org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:744)
org.springframework.orm.hibernate3.HibernateTemplate$$FastClassByCGLIB$$cf0d264a.invoke(<generated>
net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
org.springframework.orm.hibernate3.HibernateTemplate$$EnhancerByCGLIB$$8ece0e67.saveOrUpdate(<generated>
domain.core.EntityRepositoryImpl.save(EntityRepositoryImpl.java:63)
Note, I clearly do not get this issue when my facade is not wrapped within a transaction, but that is not an option for me. Note, the pojo that I hold during the update use case is detached. So, I assume my issue has to do with the fact that pojo being passed in is not managed while the getPojosForUser() operation prior to the save creates another pojo that has the same identifier as my method parameter.
I tried separate the create from the update use cases by adding a separate update API to my service that first reattaches my pojoInstance using a "getHibernateTemplate().update(pojoInstance)" API, but that ends up updating my table even before the validation occurs and I don't want that.
How do I fix my issue? What am I missing?