If you are using Hibernate 3.0 (you probably should be), saveOrUpdateCopy() is deprecated in favor of merge().
NonUniqueObjectExceptions can be a pain to deal with, especially since Hibernate doesn't give you any clean way of determining if your object in question is already represented in an open session. Session.contains() is where the Hibernate folks tend to point as a solution, but this only tells you if your exact object instance is in the session, not if a different instance having the same ID is in the session. You will see this if you dig into the Hibernate PersistenceContext source (look for checkUniqueness, isEntryFor, entitiesByKey, etc.). I'm using Spring and Spring's OSIV filter (with singleSession=true), and I've implemented a general-purpose HibernateService class which provides methods for attach(), evict(), and merge() (this is described in the Tapestry wiki, but I need to update it since I've refined my approach somwewhat since it was posted a few months ago). I generally invoke attach() (which actually does a getSession().lock(object, LockMode.NONE)) in pageBeginRender() for detached objects, but this can cause NonUnique exceptions if a previous page operation (such as the one you describe) loads a different instance of the object in question. Possible solutions (depending on your application) is to either ignore NonUniqueObjectExceptions during attach(), or to merge() instead of attach() and to replace your current object instance with the object returned by merge(). This should normally be done in pageBeginRender(). You can also try to evict() your object, but unfortunately this also just evicts the exact object instance, rather than a different object instance having the same ID. This is a case where it feels Hibernate was designed in the dark. It would be helpful if there was a Hibernate method to determine if a duplicate object already exists in the session and to code accordingly, but so far I haven't found a solution to that (short of just dealing with the thrown exception). You will also have to watch out for dirty collection exceptions, and either code to avoid them or to use a different attach() method, since session.lock is only intended to be used for unmodified objects. I have found that if I start getting dirty collection exceptions, I'm probably doing something stupid or at least sloppy. Shawn Quoting Adam Henderson Azudio <[EMAIL PROTECTED]>: > Having a problem with a NonUniqueException > > In my application I need to display, add & update Thing objects in > various places, so I've created a ThingForm component that I can > simply > drop in and pass in the required parameters and it should work. > > Page Description > A page displays some info about the ParentThing and also presents a > form to add another Thing to its set of Things, once submitted the > page > displays again with the filled in information still there so the user > > can make ammendments to the Thing and submit again. > > Domain Classes > ParentThing - An object that contains many Thing objects > ParentThingManager - A service object which handles the crud > operations > for ParentThings > Thing - An object that is associated to a ParentThing > > ParentThing 1---M Thing (Cascade="save-update") > > Tapestry Component > ThingFormComponent - A common form used in my application to add & > edit > Thing objects > > Parameters > ThingManager - A Service Manager that handles the saving of the Thing > > object using Spring/HibernateDAOs > ParentThing - An object that is contains many Thing objects as a Set > [Thing] - An optional Thing object to pass into the component & > therefore display field values > > > Page Flow > In my page spec a property is defined to create a ParentThingManager > > The id of the ParentThing is in my visit object, so in > pageBeginRender > I have code that retrieves my ParentThing from the DB (using > ParentThingManager (Spring/Hibernate DAO)) and then calls > setParentThing(pt) property on my page. > > The template contains: <span jwcid="@ThingFormComponent" > manager="ognl:thingManager" thing="ognl:thing"> > > My ThingFormComponent pageBeginRender() method creates an empty Thing > > object if necessary. > > User fills out the form and submits > > This then calls save() listener which does the following: > // Set the associations on both sides for Hibernate > getThing().setParentThing(getParentThing()); > getParentThing().getThings().add(getThing()); > > getParentThingManager().saveParentThing(getParentThing()); > > return; > > The Thing is added to the ParentThing & saved to the DB correctly > > The page redisplays with all the fields filled out, user resubmits > but > this throws a hibernate NonUniqueObjectException "a different object > > with the same identifier value was already associated with the > session: > 22, of class: com.company.Thing" > > Now I get why this is happening (I think) - because on submission the > > ParentThing is retrieved therefore bring back "Thing:22" as part of > its > Set of Things so "Thing:22" now exits in the hib session, I then > re-insert the Thing from the form which also has the id of 22 and > hibernate realises that the Thing:22 in its session is different to > the > new one and throws a wobbly (exception). > > So how do I get round this?, I'd like it to do a saveOrUpdateCopy() > on > its child Things when it does its cascade > > Am I correct in my thinking and how do I get round this. > > Will post to the hibernate forum as well. > > Many thanks, > > Adam > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: > [EMAIL PROTECTED] > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]