Makes complete sense... I've tested your suggestion and OpenJPA works as expected.
Anyway, it's weird that if you encapsulate the save/merge code in a DAO, you have to return the new attached object. It somehow invades the rest of the code, which is, well... ugly :), IMHO of course. Anyway, thanks a lot for all your time and help. Regards, Esteve En/na David Ezzio ha escrit: > Monday, September 24, 2007 > > Hi Esteve, > > I've taken a look at the test case that you made available. I've > reproduced the behavior that you are reporting. I can tell you where > the problem lies, and I've attached code for you that does what your > test case wants to do and works as expected. > > So what's the problem in your test code? > > In JPA, the basic life cycle of entities involves four states: new, > managed, detached, or removed. Entities become detached under the > following conditions (from the JPA spec): > > "3.2.4 Detached Entities > > "A detached entity may result from transaction commit if a > transaction-scoped container-managed entity manager is used (see > section 3.3); from transaction rollback (see section 3.3.2); from > clearing the persistence context; from closing an entity manager; and > from serializing an entity or otherwise passing an entity by > value—e.g., to a separate application tier, through a remote > interface, etc." > > Therefore, closing the entity manager, when the persistence context > has extended scope (the default for J2SE), causes the managed entities > to become detached. > > In your example, you create a new Parent in the runTest1 method, make > it persistent (managed), and put it in a map. You then close the > entity manager. Viola! The parent stored in the map under "OBJ" tag > has become detached. > > In the next method, runTest2, you take this Parent and add two new > children to it. The two children are new. They are not managed. You > merge this object keeping the original detached object in the map. You > close the entity manager. Result, 2 new children added to the > database, in a one-to-many relationship to the Parent. BUT, the Parent > in the map, although still detached, still has two new (not detached > nor managed) children. > > In the next method, runTest3, you take the original Parent, and add > two more new children to it. You then merge the detached Parent again. > Result, four more new children added to the database, which the Parent > has a one-to-many relationship to, but the the Parent "forgets" about > the relationship to the two children (still in the database) added in > runTest2. > > The problem is that when you merge, you get back from the merge > method, a reference to the resulting managed object. If you take that > reference and put it in the map, you'll have after commit and the > closing of the entity manager, a detached reference to a Parent with > two detached (NOT NEW) children. Then in step three, when you add two > more children, you end up with just four children in the database, > with no forgetten children. > > If you had put a version column in the Parent, I believe it would have > caught the duplicate use of the same detached version of the Parent > and thrown an OptimisticLockException in runTest3 since that version > had already been merged and committed with changes once before in > runTest2. > > Make sense? > > Cheers, > > David > >
