If you use Hibernate and Spring, but no JTA or Seam, and you have to subscribe to the session-per-request-with-detached-objects model, you may have run into the following situation: having to reattaching detached objects to the current open Hibernate session. Even with an Open-Session-In-View filter or interceptor, you may have situations where you need to perform and operation on a detached object, but its parent session is closed.
Well, there are a few ways to handle this. Jason C. showed me some code that would merge pending changes, using the merge(…) method on the Session interface. In my situation, I needed a way to attach the persistent parent to the current open session, and let the natural cascading occur. So, AOP to the rescue. I added the ReattachAdvice (below) as advice to the all my DAOs, for their “save*” and “update*” methods.
public class ReattachAdvice implements MethodBeforeAdvice {
...
public ReattachAdvice(String... inomingMethodNames) {
// store incoming method name patterns
}
/**
* @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method,Object[],Object)
*/
public void before(Method method, Object[] incomingArgs, Object target) throws Throwable {
...
if (!(target instanceof AbstractHibernateDao)) return;
final HibernateTemplate template = ((AbstractHibernateDao) target).getTemplate();
final String methodName = method.getName();
for (String pattern : namePatterns) {
// Is a handled method?
if (CommonUtil.stringMatch(pattern, methodName)) {
for (int index = 0; index < incomingArgs.length; index++) {
Object tmpArg = incomingArgs[index];
if (tmpArg instanceof Entity) {
incomingArgs[index] = handleEntity(template, (Entity) tmpArg);
}
}
return;
}
}
}
private static Entity handleEntity(HibernateTemplate template, Entity entity) {
if (entity.isPersisted()) {
try {
entity = (Entity) template.merge(entity);
} catch (StaleObjectStateException e) {
template.load(entity, entity.getId());
}
}
return entity;
}
}
Then I had to make the following addition in my Spring context files. Pre-AOP, I would have had to ensure that any method that might run into this issue, would call some re-attach method. This seems cleaner.
<bean id="reattachAdvice" class="somepackaging.ReattachAdvice">
<constructor-arg>
<list>
<value>save*</value>
<value>update*</value>
</list>
</constructor>
</bean>
...
<bean id="daoTemplate" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
<property name="interceptorNames">
<list>
<value>reattachAdvice</value>
... other advice
</list>
</property>
</bean>
Cool, but dangerous. I can’t think of the situations off the top of my head, but there are times when I thing *thank god* Hibernate was warning me there with an exception.
I think if there is a situation in your code (like deleted objects will be re-attached, etc..) good luck tracking them down.
True. I am hoping based on the docs, that removed children stayed removed during the merge. I will keep this in mind.
You don’t want to ignore these errors. What I do is to catch them and replace the entity being held in the sesssion for me and at the same time mark a flag on the entity holder so that it knows it was refreshed and the current changes lost. The UI layer is set to look for these issues and signal it to the user so they know what happened.
You shouldn’t have problems with things getting re-added to the database after being deleted if you have your unsaved value set correctly.
Nice..the GoF will be proud. The session-per-request-with-detached-objects pattern ..
Thats the only model I thump here…and the only one that makes sense to me. All objects returning back to the UI are “detached”.
The slew of pissy emails i sent a while back was regarding merging of such detached objects and causing all sorts of troubles with cascades, deletes, etc.
What Advice(ha) does Hibernate provide on this exactly? Do they recommend using AOP? (ok i’m too lazy to go find out – just tell me)..
Update: Removed the lock(…) call. That actually didn’t help at all.
e.g.: http://forum.hibernate.org/viewtopic.php?t=959555