[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