I've got a BeanEditForm for my User entity which has a version field:

    @Version
    public long getVersion() {
        return version;
    }
    public void setVersion(long version) {
        this.version = version;
    }

I've got an admin screen to edit a user, and I would like to make sure I
don't overwrite changes made by the user (they can change their password,
for example) or by the application, while I'm on the edit screen. I've tried
a few things, but I always see the same behavior: any changes in the
database get overwritten when I hit "save" in the BeanEditForm.

Test 1:
EditUser.tml:
<t:BeanEditForm object="user" t:id="editUserForm"/>

EditUser.java:
    @CommitAfter
    public Object onSuccessFromEditUserForm() {
        return UserIndex.class;
    }

I open the EditUser page in the browser, I change the user in the database
(increasing the version field by one), then I hit save in the browser,
expecting Hibernate to throw an exception. Instead, it saves the changes,
increasing the version again. Eg I start at version 0, open the page, edit
the db to change a field and set version to 1, then I hit save in the
browser, it clobbers my changes and sets version to be 2.


Test 2:
I tried out the code from JumpStart
http://jumpstart.doublenegative.com.au/jumpstart/examples/easycrud/update/2which
says it handles versioning. My code now looks like this:
tml:
<t:BeanEditForm object="user" t:id="editUserForm">
<p:version>
<t:hidden value="user.version"/>
</p:version>
</t:BeanEditForm>

The java code is the same as Test 1.

Again, the changes get clobbered.

Test 3:
I noticed that the hidden field didn't have an ID set, so I tried:
<t:hidden value="user.version" t:id="version"/>
Same thing, changes get overwritten.

Test 4:
Managing the version myself. In the tml I have:
    <t:BeanEditForm object="user" t:id="editUserForm">
        <p:version>
            <t:hidden t:id="versionWhenLoaded"/>
        </p:version>
    </t:BeanEditForm>

In java, I have:
    @PageActivationContext
    private User user;

    @Property
    private long versionWhenLoaded;

    public void setupRender() {
        versionWhenLoaded = user.getVersion();
    }

    @CommitAfter
    public Object onSuccessFromEditUserForm() {
        user.setVersion(versionWhenLoaded);
        return UserIndex.class;
    }

Again, changes get overwritten. I really would expect the last case to work
- maybe I need to do something special in Hibernate to set the version
field?

I'm using tapestry 5.2.4, the tapestry-hibernate dependency (so Hibernate
3.6.0-Final).

I've confirmed that Hibernate does throw a
StaleObjectStateExceptionexception when it tries to make changes to
the user at the same time, by
having another page which does, essentially:
User user = userDAO.findById(1);
timeProvider.sleep(10000);
user.setFirstName("something different");
sessionManager.commit();
I load it twice, and the second page throws StaleObjectStateException.

Any ideas?

Reply via email to