I am working with a legacy database. Consider these tables: Clients and ClientClasses.
ClientClasses is a simple table with 2 columns: id and class. class is an integer. ClientClasses has a many to one relationship with Clients. id is the foreign key into Clients.
Clients has many columns. Its primary key is id.
When I load a Clients object, I get all its classes. The Application's User uses a checkbox group to add / remove classes and then Update. If someone else (another User) has changed the classes of this Clients object, I want the Update to fail with something like a StaleStateException. Presently, this happens only if the User deletes a class that someone else had already deleted (during user think-time). I want Update to fail if ANYTHING has changed in the ClientClasses table with this Clients' id.
I am NOT using POJO. I am using dynamic mapping, hence you will see entity-name in my xml mappings.
<class entity-name="ClientsEntity" table="Clients" dynamic-update="true" dynamic- insert="true" optimistic-lock="all" lazy='true'> <id name="id" type="int" column="id"> <generator class="native"/> </id> ... <bag name="clientclassesEntity" lazy='true' inverse='true' cascade='all-delete-orphan' fetch='select'> <key column='id' /> <one-to-many entity-name='ClientClassesEntity' /> </bag> </class>
<class dynamic-insert="true" dynamic-update="true" entity-name="ClientClassesEntity" optimistic-lock="all" table="ClientClasses" > <composite-id > <key-property name='class' type='integer' ></key-property> <key-property name='id' type='integer' ></key-property> </composite-id> </class>
I have enabled hibernate's show_sql, format_sql, and hibernate.use_sql_comments properties and here is the output when I delete a class that has already been deleted by someone else. Recall that this works as I want.
Example (Works): the User sees that this Clients object has classes 1, 8, 16, 32, 64. The User unchecks 8 and clicks Update. (Meanwhile, another User has already deleted 8.)
Hibernate: /* delete ClientClassesEntity [0] */ delete from ClientClasses where class=? and id=?
Rollback from HibernateException successful.
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
HibernateLog --> 10:33:54 INFO org.hibernate.event.internal.DefaultDeleteEventListener - HHH000114: Handling transient entity in delete processing
And User sees a popup window with this:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [ClientClassesEntity#{id=15014, class=8}]
====================
Next Example (does NOT work): I restart the application and the User sees that the Clients object has classes 1, 16, 32, 64. They check the box for 128 and click Update. (Meanwhile, another User has already inserted 128.)
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
No Exception was thrown. I want this User to be notified that the underlying data changed beneath him/her.
====================
Next Example (does not work): I restart the application and the User sees that this Clients object has classes 1, 16, 32, 64, 128. They uncheck 16, 32, 64 and check 2. So, they think that the classes are going to be 1, 2, 128. (But before they click Update, another User has deleted 1 and 128.) **Our User is not informed that the data changed.** Their Update goes through. I would like a StaleObjectStateException.
Hibernate: /* get current state ClientClassesEntity */ select clientclas_.class, clientclas_.id from ClientClasses clientclas_ where clientclas_.class=? and clientclas_.id=?
Hibernate: /* insert ClientClassesEntity */ insert into ClientClasses (class, id) values (?, ?)
Hibernate: /* delete ClientClassesEntity [0] */ delete from ClientClasses where class=? and id=?
Hibernate: /* delete ClientClassesEntity [0] */ delete from ClientClasses where class=? and id=?
Hibernate: /* delete ClientClassesEntity [0] */ delete from ClientClasses where class=? and id=?
The database now holds just the class 2 for this Clients object, but our User thinks it holds classes 1, 2, 128.
I am using the strategy of one session per conversation. So, I don't have detached objects to reattach.
How can I get Hibernate to do a re-select before insertion or deletion and throw an exception if the data has changed. I don't want to automatically re-select on other tables--just ClientClasses (ClientClassesEntity).
Any ideas?
|