The down side to embedding database IDs in your HTML form is they can be changed by the user before POSTing them back to your application, which can cause all sorts of problems.
/dev/mrg -----Original Message----- From: Jim Steinberger [mailto:[EMAIL PROTECTED] Sent: Sunday, July 09, 2006 6:56 PM To: Tapestry users Subject: RE: Best practice for new/edit object page? Hi Malin, Here are my thoughts: 1. Embedding the ID into the page (along with every other property of the entity). Benefit: After the rewind phase sets all the OGNL-mapped properties to your page-property-object, you can simply pass that object directly to the service/persistence layers to be saved. Downside: This only works if you're comfortable embedding all of the object's properties in the page. There's a security issue here (if it's not an SSL connection, for example, you wouldn't want a user's password or social security number being transferred in cleartext). There's a practicality issue, too; if your object has a lot of associated entities, it'd probably be too cumbersome to embed the entire object-graph inside the page. 2. Embedding the ID into the page (along with, only, properties you intend to be updatable) Downside: I don't know of a great way to do this. As you asked: " but this means I will have to redo EventServices.getEvent(eventId) after postback. This could maybe be OK but where do I put the code?" After all, you need the ID in order to query out the object, but that ID isn't set via OGNL until after the rewind phase. The problem here, then, is that you'd have to manually set all the properties to the object in your listener. 3. Keeping the ID in the session Implementation: Instead of setting the ID to the visit object (or another application-state-object), declare the ID as a property of the page, and also declare it to be persistent (e.g. the @Persist annotation). Have your page implement the PageBeginRenderListener, and in your pageBeginRender method, if the ID is not null, "get" the object (I'm using Hibernate semantics) if you're not rewinding, and "load" the object if you are. If you're rewinding, then, you'll query out the object as it currently appears in the database, and then the rewind phase will set all the OGNL mapped properties to it (which are the only ones you intend to be mutable). You can then pass this to the service/persistence layer in your listener. Downside: Very slight RAM overhead (I try to avoid persistent properties/session data as much as possible, but individual Integer objects should take awhile to add-up [I say perhaps naively]). Benefit: Only the properties intended to be edited will be sent to the client. This also mitigates, by a degree, the synchronization issue inherent to this. Consider the following scenario: Page 1 edits properties A and B. Page 2 edits properties C and D. Using scenario 1 above, when user Alpha loads page 1, he sees properties A and B, and properties C and D are embedded in the page. User Beta loads page 2, and has the reverse situation. If user Beta then submits the form, properties C and D will be updated. When user Alpha submits /his/ form, he'll be updating C and D back to what they were originally. This scenario still exists in scenario 3 above -- but the time-window of this is much much smaller: properties C and D would only be reverted if user Beta's save occurs between the Page 1's pageBeginRender method and listener (since it loads the object in the former but doesn't save it until the latter). Still, even this smaller window could well be unacceptable if your interface allows for this scenario. I don't have a great suggestion for this, but I'm pretty sure they're there; that people have explored having transactions that span user-requests. Anyway, I'm currently migrating toward scenario 3, but I'm certainly open to other suggestions, as I was about to ask exactly this question of the list : ) Jim -----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Malin Ljungh Sent: Saturday, July 08, 2006 5:21 PM To: Tapestry users Subject: Best practice for new/edit object page? Hi everyone, I'm pretty much a newbie on Tapestry and need some help. I'm building a simple web application for administering some data in a database. I use Hibernate for database connection. I'll need several pages that will handle insert of new record to table or editing an existing record. I wan't to use the same page for insert and edit. My question is basically: How should I build my pages and how should I handle state between postbacks? Let me take an example - I have a model object called Event, a page ListEvents and a page EditEvent. This is the essentials of my EditEvent.java: public abstract Event getEvent(); public abstract void setEvent(Event event); public void pageBeginRender(PageEvent event) { if(getEvent() == null) // new Event setEvent(new Event()); } Could/should the thing in pageBeginRender be done by injection instead? And this is the link between the Event list and the EditEvent page in ListEvents.java: @InjectPage("EditEvent") public abstract EditEvent getEditEvent(); public IPage editEvent(int eventId) { EditEvent editEvent = getEditEvent(); editEvent.setEvent(EventServices.getEvent(eventId)); return editEvent; } where EventServices.getEvent fetches Event from DB. How should I handle state between postbacks? I have put my eventId in a Hidden in the EditEvent.html like this: <input jwcid="@Hidden" value="ognl:event.eventId" /> but this means I will have to redo EventServices.getEvent(eventId) after postback. This could maybe be OK but where do I put the code? Or should I store the Event instance in my visit state? This must be one of the most common scenarios so I guess you all know how it should be done - please tell me :) Malin --------------------------------------------------------------------- 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]