views:

264

answers:

2

Hi!

I have 2 entities: Parent and Child in a one-to-many relationship. The Parent is versioned, i.e. has a @Version field. My goal is to synchronize changes to both Parent and Child entities on the Parent's version.

E.g. one thread updates the Parent and another one updates one of it's Childs, this should cause an OptimisticLockException.

Is it possible?

I tried adding a @PreUpdate to the Child which would increment the version of it's Parent, but that didn't help because Hibernate seems to execute listeners only after it checks versions so the transaction commits successfully anyway.

If it is possible, how can it be implemented?

+1  A: 

Did you try making the Child a component instead of an entity?

The default Hibernate operations might be much more aligned with your requirements. The idea is that the Parent is a real entity, while the Child is considered an element of a bigger whole.

In Hibernate, this should be considered the default parent-child relationship. Parent-Child relation between entities are less natural, although possible.

KLE
I think that's not an option for me. The Child is a first-class entity with it's ID and state and it should remain that way. Though your idea is definately a solution, it is not applicable for me
artemb
OK, I understand. . . Your requirement may be possible with Hibernate, but I don't remember what you should try... sorry.
KLE
+1  A: 

First of all, there are two issues here that need to be clarified:

  1. I take it you're trying to catch updates made to a particular Child instance rather than collection modifications (e.g. new Child being added / old removed). The latter will increment parent's version by default.

  2. When you say "one thread updates Parent" and "another updates Child" I'm assuming that changes are immediately flushed. In other words, the sequence of events is: parent is updated and persisted (changes flushed; transaction committed1); another thread tries to update child which points to the previous version of parent and fails. If that's not the case, optimistic locking is not going to help you.

1 You may be able to work around the "transaction committed" bit by setting appropriate isolation level, but that's likely to cause more problems then it solves in concurrent environment. You can't work around "immediate flush" requirement.

Assuming the above assumptions are correct, you'll need to use EntityManager.lock() method to lock Parent prior to updating your Child instance. See LockModeType and Hibernate EntityManager docs for details.

ChssPly76