Thank you. Especially Jim, you have understood my "problem" perfectly!
The thing is I have a hibernate OR-mapping with lots of relationships and
attributes which the user should not edit or see at all in the edit page.

I think I'll use your #3 - keeping the ID in the session using @Persist and
reload entity from database at postback.
My wonder is then - how do I detect the "new entity" scenario? If the user
enters the edit page for an existing item and then clicks the link to create
a new item I will have to reset the ID, am I right? My current PageLink will
not do in that case.

Malin

On 7/10/06, Jim Steinberger <[EMAIL PROTECTED]> wrote:

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]


Reply via email to