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?