Jim, Oooh! That's nasty and I was unaware of the issue (assigning a primary key, but not really committing the transaction). Do you have documentation of the phenomenon or maybe some unit test code that would exhibit that behavior (I'm not calling you a liar; I just want to see it in action and maybe try to figure out how to code around it)?
Thanks, James -----Original Message----- From: Jim Steinberger [mailto:[EMAIL PROTECTED] Sent: Tuesday, May 02, 2006 8:16 PM To: Tapestry users Subject: RE: Insert/Update pages and Hibernate Paul, Thanks much -- I take your points well; there are certainly some things I'm considering changing. If you could, though, I'm having trouble relating them to this specific case; here's a basic listener: public IPage saveManufacturer() { try { getManufacturerService().createManufacturer(getManufacturer()); } catch (Exception e) { setError("Could not create Manufacturer: " + e.getMessage()); return this; } } You suggested throwing away the bad object (getManufacturer()), but if I do that, I'm throwing away all the data the user entered, forcing them to retype everything -- and I couldn't query that from persistence because it was never persisted in the first place (the primary key on my object is invalid because the INSERT never happened). I had previously assumed that Hibernate not change my objects if the database transaction didn't complete. e.g. if the INSERT fails, I assumed Hibernate wouldn't set my primary key. I only found out recently that this was a bad assumption; if something goes wrong, the objects passed in can be mutated. _Effective Java_ would tell me to, then, clone my objects before passing them to an API that could potentially mutate them, since I need to keep the original data around (the user input). But I've never seen anyone doing this, so I'm asking about this situation here because either I'm missing something or a lot of other people are. Jim -----Original Message----- From: Paul Cantrell [mailto:[EMAIL PROTECTED] Sent: Tuesday, May 02, 2006 7:12 PM To: Tapestry users Subject: Re: Insert/Update pages and Hibernate There are several practices you can use to avoid painting yourself into this corner: (1) Probably the best and simplest: Use a straightforward transaction- per-request model, and don't ever hold on to persistent objects between requests.* Instead, hold on to the IDs of your persistent objects. Think of the persistent objects as a fleeting view of the app's persistent state, a view that will vanish at the end of the request. Keep enough user input and working values in your page to be able to get all the way from a cleanly fetched object to a committable one, in one go -- instead of poking and prodding the persistent object to its ultimate committable state across several requests. Having a custom Tapestry SqueezeAdaptor for your persistent objects makes this quite simple: you page properties can all look like the full persistent objects, but Tapestry will only store the ID between requests. It sounds like your problems are cause by having a broken persistent object dangling from your page. Solution? Don't attach it to the page! Throw it away when the request is done. Let your listeners fetch it again clean next time. (2) On the heels of (1), always roll back on error. You can do this in your transaction interceptor or servlet filter; it's also possible to do it in validator / listener methods. A mix of both may be appropriate. Sounds like you may already be doing this -- but when combined with (1), you know that your DB and your objects are clean after a failure, and only the page itself remains messy. (3) Make your domain objects "fail fast:" enforce constraints up front, and when possible, don't let objects get into an invalid state to begin with. In your case, that means not storing the PK back to the page until the create has succeeded. (4) To make (3) really work, ensure your domain objects observe strict failure atomicity. See _Effective Java_ for an explanation. (Order a copy if you don't own it! It's a marvelous book.) I hope that is helpful. Cheers, Paul * In some situations, holding persistent objects between requests is the right approach. However, I believe these situations are rare. The pitfalls of this approach are large, and the performance benefits are often overstated (especially if you use caching). On May 2, 2006, at 5:42 PM, Jim Steinberger wrote: > In Tapestry, we use model objects as the data-buffer. If we're > editing an entity, and something goes wrong, we can set an > errorMessage > property, "return this;", and expect the user to see the form still > filled-out with what they'd just typed with an explanation of what > went > wrong. > > If you're using Hibernate, however, I don't think this use-case is > guaranteed; mainly because I'm currently dealing with cases where it > isn't. > > What I mean by that: If something goes wrong in a Hibernate > session, > your entities are not guaranteed to be left in a stable state. i.e. > they're not guaranteed to match their counterparts in the persistence > layer. > > In my case, I'm trying to insert an object with some not-null > properties left as null. Hibernate sets the primary key of my object > (when it queries my Postgres sequence), but then fails on the actual > entity-insert. An exception is thrown, but the primary key is left on > my object. Since my Tapestry page is designed to handle both creating > and updating this entity -- and since it does this by testing > whether or > not an object's primary key exists -- the user is told there was a > problem, but as far as Tapestry is concerned, the user is now editing > the entity, not creating it. > I can hack it by explicitly setting the primary key to be null > where I > catch the Exception, but who knows what else Hibernate might be > mutating > without going through the source code. > > Am I crazy, or does this Hibernate practice mean that, everywhere we > expect to be able to use an object even if something goes wrong in > Hibernate, we have to clone our entity first or open ourselves up to > potential problems? Are people doing this? > > > Jim _________________________________________________________________ Piano music podcast: http://inthehands.com Other interesting stuff: http://innig.net --------------------------------------------------------------------- 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] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]