[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2796) Generated version are incremented by Hibernate
Tommy Knowlton (JIRA)
noreply at atlassian.com
Thu Jan 22 14:02:40 EST 2009
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2796?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=32178#action_32178 ]
Tommy Knowlton commented on HHH-2796:
-------------------------------------
Similarly, when persisting an entity mapped using annotations (as below), Hibernate modifies the @Version field's value internally and then fails (throwing StaleObjectStateException) when attempting to insert the database row.
@Entity
@Table(name = "ITEM")
public class Item implements Serializable
{
@Id
@Column(name = "ITEM_ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ItemIdGenerator")
@SequenceGenerator(name = "ItemIdGenerator", sequenceName = "SQ_ITEM_ID")
protected Long id;
@Generated(GenerationTime.ALWAYS) // (must be) populated by database trigger, because shared with other applications
@Version
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "MODIFIED_DATE", insertable = false, updatable = false)
protected Date modifiedDate;
// other mapped fields
// ...
}
// Hibernate 3.2.6 GA, Oracle 10.2
I note that this is apparently intended to work, as I gather from the Hibernate Annotations reference, section 2.4.3 contains the following advice:
<blockquote>
@Version properties cannot be @Generated(INSERT) by design, it has to be either NEVER or ALWAYS.
</blockquote>
> Generated version are incremented by Hibernate
> ----------------------------------------------
>
> Key: HHH-2796
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2796
> Project: Hibernate Core
> Issue Type: Bug
> Components: core
> Affects Versions: 3.2.1
> Environment: 3.2.1, Oracle 10g
> Reporter: Heba Tawfik
>
> Creating a new entity which it's version is set to generated="always" & saving it, then in the same session adding an object to any of its on-to-many relationships is throwing a StaleObjectStateException.
> To regenerate the problem, consider the following code
> 1- departement.hbm.xml :
> ----------------------------------------
> <hibernate-mapping package="com.myproject.domain">
> <class name="Departement" table="Departement">
> <id name="id">
> <column name="dept_id" />
> </id>
> <version column="version" generated="always" name="version" type="integer" unsaved-value="null" />
> <property name="name" column="name" />
> <bag name="employees" inverse="true" cascade="all" lazy="true">
> <key column="dept_id"></key>
> <one-to-many class="Employee" />
> </bag>
> </class>
> </hibernate-mapping>
> 2- employee.hbm.xml :
> --------------------------------------
> <hibernate-mapping package="com.myproject.domain">
> <class name="Employee" table="Employee">
> <id name="id">
> <column name="employee_id" />
> </id>
> <property name="firstName" column="first_name" />
> <property name="lastName" column="last_name" />
> <property name="age" column="age" />
> <property name="salary" column="salary" />
> <many-to-one cascade="none"
> class="com.myproject.domain.Departement"
> column="dept_id" embed-xml="true" insert="false"
> name="department" not-null="false"
> unique="false" update="false" not-found="ignore">
> </many-to-one>
> </class>
> </hibernate-mapping>
> 3- Departement.Java
> ---------------------------
> package com.myproject.domain;
> import java.util.ArrayList;
> import java.util.List;
> public class Departement extends BaseDepartement{
> int id;
> String name;
> List employees;
> Integer version;
> public int getId() {
> return id;
> }
> public void setId(int id) {
> this.id = id;
> }
> public String getName() {
> return name;
> }
> public void setName(String name) {
> this.name = name;
> }
> public Integer getVersion() {
> return version;
> }
> public void setVersion(Integer version) {
> this.version = version;
> }
> public List getEmployees() {
> return employees;
> }
> public void setEmployees(List employees) {
> this.employees = employees;
> }
>
> public void addToEmployeeList(Employee emp)
> {
> if(employees==null)
> {
> setEmployees(new ArrayList());
> }
> employees.add(emp);
> }
> }
> 4- Employee.Java :
> ---------------------------
> package com.myproject.domain;
> public class Employee {
>
> int id;
> String firstName;
> String lastName;
> int age;
> int salary;
> BaseDepartement department;
>
> public BaseDepartement getDepartment() {
> return department;
> }
> public void setDepartment(BaseDepartement department) {
> this.department = department;
> }
> public int getAge() {
> return age;
> }
> public void setAge(int age) {
> this.age = age;
> }
> public String getFirstName() {
> return firstName;
> }
> public void setFirstName(String firstName) {
> this.firstName = firstName;
> }
> public int getId() {
> return id;
> }
> public void setId(int id) {
> this.id = id;
> }
> public String getLastName() {
> return lastName;
> }
> public void setLastName(String lastName) {
> this.lastName = lastName;
> }
> public int getSalary() {
> return salary;
> }
> public void setSalary(int salary) {
> this.salary = salary;
> }
> }
> 4- Code To Test :
> ------------------------
> public static void main(String args[]) throws Exception
> {
> SessionFactory factory = new Configuration().configure("com/myproject/config/hibernate.cfg.xml").buildSessionFactory();
> Session session = factory.openSession();
> Transaction transaction = session.beginTransaction();
> Departement aDept =new Departement();
> aDept.setId(10);
> aDept.setName("Test");
> session.save(aDept);
> transaction.commit();
> transaction = session.beginTransaction();
> Employee emp=new Employee();
> emp.setId(10);
> emp.setFirstName("test");
> emp.setLastName("test");
> emp.setSalary(10);
> emp.setAge(10);
> emp.setDepartment(aDept);
> aDept.addToEmployeeList(emp);
> session.saveOrUpdate(aDept);
> transaction.commit();
> session.close();
> }
> On the database, the default value for version cloumn is set to "1" and a trigger is defined as follow on the Departement table:
> create or replace
> TRIGGER TRIGGER1
> BEFORE UPDATE ON DEPARTEMENT
> FOR EACH ROW
> BEGIN
> :new.version:= :old.version + 1;
> END;
> Upon executing the above code, the following is the hibernate logging :
> automatically flushing session
> /* insert com.eds.myproject.domain.Departement
> */ insert
> into
> Departement
> (name, dept_id)
> values
> (?, ?)
> binding 'Test' to parameter: 1
> binding '10' to parameter: 2
> /* get generated state com.eds.myproject.domain.Departement */ select
> departemen_.version as version1_
> from
> Departement departemen_
> where
> departemen_.dept_id=?
> binding '10' to parameter: 1
> returning '1' as column: version1_
> before transaction completion
> after transaction completion
> automatically flushing session
> /* get current state com.eds.myproject.domain.Employee */ select
> employee_.employee_id,
> employee_.first_name as first2_0_,
> employee_.last_name as last3_0_,
> employee_.age as age0_,
> employee_.salary as salary0_
> from
> Employee employee_
> where
> employee_.employee_id=?
> binding '10' to parameter: 1
> /* insert com.eds.myproject.domain.Employee
> */ insert
> into
> Employee
> (first_name, last_name, age, salary, employee_id)
> values
> (?, ?, ?, ?, ?)
> binding 'test' to parameter: 1
> binding 'test' to parameter: 2
> binding '10' to parameter: 3
> binding '10' to parameter: 4
> binding '10' to parameter: 5
> /* update
> com.eds.myproject.domain.Departement */ update
> Departement
> set
> name=?
> where
> dept_id=?
> and version=?
> binding 'Test' to parameter: 1
> binding '10' to parameter: 2
> binding '2' to parameter: 3
> Could not synchronize database state with session
> org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.eds.myproject.domain.Departement#10]
> at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1714)
> at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2357)
> at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2257)
> at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2557)
> at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
> at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
> at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
> at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
> at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
> at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
> at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
> at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
> at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
> at com.eds.myproject.test.Test.main(Test.java:43)
> org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.eds.myproject.domain.Departement#10]
> at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1714)
> at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2357)
> at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2257)
> at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2557)
> at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
> at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
> at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
> at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
> at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
> at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
> at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
> at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
> at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
> at com.eds.myproject.test.Test.main(Test.java:43)
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
More information about the hibernate-issues
mailing list