-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: composite-id and version results in ObjectStaleStateExceptio
PostPosted: Mon Sep 13, 2004 12:12 pm 
Newbie

Joined: Fri Mar 19, 2004 3:53 pm
Posts: 6
I am attempting to use the "version" mapping to indicate to hibernate the state of the Employee object that I have mapped. I use a composite-id for the key to a legacy database. The key consistes of two properties fiscalYear and documentNumber. I also map a "version" property that has a column in the database named "LOG_COUNTER". I want to use Hibernate's automatic versioning to handle the state of my objects but every time I execute Hibernate's saveOrUpdate method after having populated my Employee object with test data I get an ObjectStaleStateException.
I am using Spring in this application. So I make use of the HibernateTemplate to execute Hibernate's built-in methods.
Code:
   public void saveEmployee(Employee employee) {
      this.getHibernateTemplate().saveOrUpdate(employee);
   }

The wiring of everything in the application has been tested thoroughly and is solid. I feel like I must be mapping the "version" or the "composite-id" incorrectly. Is there anything I must do to the version attribute of the Employee class before calling the saveOrUpdate method?
Thanks in advance,
Christopher Kwiatkowski

Hibernate version:2.1.6

Mapping documents:
Code:
<hibernate-mapping>
   <class name="org.appfuse.model.Employee" table="bbab20e" lazy="true">
      <composite-id name="documentId" class="org.appfuse.model.DocumentId">
         <key-property name="fiscalYear"
                    column="BBAB20E_CDFSYR"
                    type="string"/>
         <key-property name="documentNumber"
                    column="BBAB20E_NODOCU"
                    type="string"/>
      </composite-id>
      
      <version name="version" column="LOG_COUNTER" unsaved-value="null"/>
            
      <property name="firstName" column="BBAB20E_NMEMFS" />
      <property name="lastName" column="BBAB20E_NMEMLS" />   
      <property name="gender" column="BBAB20E_CDSEX"/>                  
      <property name="middleName" column="BBAB20E_NMEMMD" not-null="false"/>               
      <property name="suffix" column="BBAB20E_NMEMSF" not-null="false"/>
   </class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

Full stack trace of any exception that occurs:
Code:
   

    [junit] ------------- ---------------- ---------------
    [junit] Testcase: testSaveEmployee(org.appfuse.service.EmployeeManagerTest):
        Caused an ERROR
    [junit] Row was updated or deleted by another transaction (or unsaved-value
mapping was incorrect) for org.appfuse.model.Employee instance with identifier:
org.appfuse.model.DocumentId@d0220c[
    [junit]   fiscalYear=9999
    [junit]   documentNumber=999990003
    [junit] ]; nested exception is net.sf.hibernate.StaleObjectStateException: R
ow was updated or deleted by another transaction (or unsaved-value mapping was i
ncorrect) for org.appfuse.model.Employee instance with identifier: org.appfuse.m
odel.DocumentId@d0220c[
    [junit]   fiscalYear=9999
    [junit]   documentNumber=999990003
    [junit] ]
    [junit] org.springframework.orm.hibernate.HibernateOptimisticLockingFailureE
xception: Row was updated or deleted by another transaction (or unsaved-value ma
pping was incorrect) for org.appfuse.model.Employee instance with identifier: or
g.appfuse.model.DocumentId@d0220c[
    [junit]   fiscalYear=9999
    [junit]   documentNumber=999990003
    [junit] ]; nested exception is net.sf.hibernate.StaleObjectStateException: R
ow was updated or deleted by another transaction (or unsaved-value mapping was i
ncorrect) for org.appfuse.model.Employee instance with identifier: org.appfuse.m
odel.DocumentId@d0220c[
    [junit]   fiscalYear=9999
    [junit]   documentNumber=999990003
    [junit] ]
    [junit] net.sf.hibernate.StaleObjectStateException: Row was updated or delet
ed by another transaction (or unsaved-value mapping was incorrect) for org.appfu
se.model.Employee instance with identifier: org.appfuse.model.DocumentId@d0220c[

    [junit]   fiscalYear=9999
    [junit]   documentNumber=999990003
    [junit] ]
    [junit]     at net.sf.hibernate.persister.AbstractEntityPersister.check(Abst
ractEntityPersister.java:501)
    [junit]     at net.sf.hibernate.persister.EntityPersister.update(EntityPersi
ster.java:672)
    [junit]     at net.sf.hibernate.persister.EntityPersister.update(EntityPersi
ster.java:642)
    [junit]     at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate
.java:52)
    [junit]     at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java
:2414)
    [junit]     at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:23
68)
    [junit]     at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2236
)
    [junit]     at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTrans
action.java:61)
    [junit]     at org.springframework.orm.hibernate.HibernateTransactionManager
.doCommit(HibernateTransactionManager.java:386)
    [junit]     at org.springframework.transaction.support.AbstractPlatformTrans
actionManager.commit(AbstractPlatformTransactionManager.java:316)
    [junit]     at org.springframework.transaction.interceptor.TransactionInterc
eptor.invoke(TransactionInterceptor.java:211)
    [junit]     at org.springframework.aop.framework.ReflectiveMethodInvocation.
proceed(ReflectiveMethodInvocation.java:138)
    [junit]     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(J
dkDynamicAopProxy.java:148)
    [junit]     at $Proxy0.saveEmployee(Unknown Source)
    [junit]     at org.appfuse.service.EmployeeManagerTest.testSaveEmployee(Empl
oyeeManagerTest.java:73)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    [junit]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcces
sorImpl.java:39)
    [junit]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMet
hodAccessorImpl.java:25)



Name and version of the database you are using:
mysql-4.0.18-win
mysql-connector-java-3.0.11-stable

The generated SQL (show_sql=true):
[junit] ------------- Standard Output ---------------
[junit] Hibernate: update bbab20e set LOG_COUNTER=?, BBAB20E_NMEMFS=?, BBAB2
0E_NMEMLS=?, BBAB20E_CDSEX=?, BBAB20E_NMEMMD=?, BBAB20E_NMEMSF=?, BBAB20E_TXSTR1
=?, BBAB20E_TXSTR2=?, BBAB20E_TXCTHM=?, BBAB20E_TXSTHM=?, BBAB20E_CDZPHM=?, BBAB
20E_NOBLDG=?, BBAB20E_NMBLDG=?, BBAB20E_NOFLOR=?, BBAB20E_NOROOM=?, BBAB20E_NOPH
HM=?, BBAB20E_NOPHOF=? where BBAB20E_CDFSYR=? and BBAB20E_NODOCU=? and LOG_COUNT
ER=?
[junit] Hibernate: select employee0_.BBAB20E_CDFSYR as BBAB20E_1_0_, employe
e0_.BBAB20E_NODOCU as BBAB20E_2_0_, employee0_.LOG_COUNTER as LOG_COUN3_0_, empl
oyee0_.BBAB20E_NMEMFS as BBAB20E_4_0_, employee0_.BBAB20E_NMEMLS as BBAB20E_5_0_
, employee0_.BBAB20E_CDSEX as BBAB20E_6_0_, employee0_.BBAB20E_NMEMMD as BBAB20E
_7_0_, employee0_.BBAB20E_NMEMSF as BBAB20E_8_0_, employee0_.BBAB20E_TXSTR1 as B
BAB20E_9_0_, employee0_.BBAB20E_TXSTR2 as BBAB20E10_0_, employee0_.BBAB20E_TXCTH
M as BBAB20E11_0_, employee0_.BBAB20E_TXSTHM as BBAB20E12_0_, employee0_.BBAB20E
_CDZPHM as BBAB20E13_0_, employee0_.BBAB20E_NOBLDG as BBAB20E14_0_, employee0_.B
BAB20E_NMBLDG as BBAB20E15_0_, employee0_.BBAB20E_NOFLOR as BBAB20E16_0_, employ
ee0_.BBAB20E_NOROOM as BBAB20E17_0_, employee0_.BBAB20E_NOPHHM as BBAB20E18_0_,
employee0_.BBAB20E_NOPHOF as BBAB20E19_0_ from bbab20e employee0_ where employee
0_.BBAB20E_CDFSYR=? and employee0_.BBAB20E_NODOCU=?
Debug level Hibernate log excerpt:

[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 13, 2004 1:17 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
1- Code between sessionFactory.openSession() and session.close():
2- are you sure you know how saveOrUpdate works?
3- are you sure of your equals/hashcode implementation?

_________________
Anthony,
Get value thanks to your skills: http://www.redhat.com/certification


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 13, 2004 2:06 pm 
Newbie

Joined: Fri Mar 19, 2004 3:53 pm
Posts: 6
I apologize for the omission of the code.

The following is the test I am running.
Code:
public class EmployeeManagerTest extends TestCase{
   private static Log log = LogFactory.getLog(EmployeeManagerTest.class);
   private ApplicationContext ctx;
   private Employee employee;
   private EmployeeManager mgr;
   
   protected void setUp() throws Exception{
      String[] paths = {"/WEB-INF/applicationContext.xml"}; // there could be multiple context files
      ctx = new ClassPathXmlApplicationContext(paths);
      mgr = (EmployeeManager) ctx.getBean("employeeManager");
   }
   
   protected void tearDown() throws Exception{
      employee = null;
      mgr = null;
   }
   
   public static void main(String[] args){
      TestRunner.run(EmployeeDAOTest.class);
   }
   
   public void testSaveEmployee() throws Exception{
      employee = new Employee();
      employee.setFirstName("Geraldo");
      employee.setLastName("Rivera");
      employee.setMiddleName("Joe");
      employee.setGender("M");
      employee.setSuffix("Jr.");
      DocumentId documentId = new DocumentId("9999","999990003");
      employee.setDocumentId(documentId);
      
      Address homeAddress = new Address("15 Stafford Drive", "", "Athens", "GA", "30605");
      employee.setHomeAddress(homeAddress);
      
      Building building = new Building(0004, "Business Services");
      WorkAddress workAddress = new WorkAddress("","","","","",building,021, 004);
      employee.setWorkAddress(workAddress);
      
      PhoneNumber phoneNumber = new PhoneNumber("555-555-5555");
      
      employee.setHomePhoneNumber(phoneNumber);
      employee.setWorkPhoneNumber(phoneNumber);
      
      mgr.saveEmployee(employee);
      log.info(employee);
      assertTrue(employee.getFirstName() != null);
   }

   public void testRemoveEmployee() throws Exception{
      DocumentId documentId = new DocumentId("9999","999990003");
      employee = new Employee();
      employee.setDocumentId(documentId);
      mgr.removeEmployee(employee.getDocumentId());
      if(log.isDebugEnabled()){
         log.debug("removing employee record ... fiscalYear:"+documentId.getFiscalYear()+ " documentNumber:"+documentId.getDocumentNumber());
      }
      assertNull(mgr.getEmployee(documentId));
   }   
}


The following is the employeeDAOHibernate class that extends Spring's HibernateDaoSupport:

Code:
public class EmployeeDAOHibernate extends HibernateDaoSupport implements EmployeeDAO{
   private Log log = LogFactory.getLog(EmployeeDAOHibernate.class);
   /* (non-Javadoc)
    * @see org.appfuse.dao.EmployeeDAO#getEmployees()
    */
   public List getEmployees() {
      return this.getHibernateTemplate().find("from Employee");
   }
   /* (non-Javadoc)
    * @see org.appfuse.dao.EmployeeDAO#getEmployee(org.appfuse.model.DocumentId)
    */
   public Employee getEmployee(DocumentId documentId) {
      return (Employee) this.getHibernateTemplate().get(Employee.class, documentId);
   }
   /* (non-Javadoc)
    * @see org.appfuse.dao.EmployeeDAO#saveEmployee(org.appfuse.model.Employee)
    */
   public void saveEmployee(Employee employee) {
      this.getHibernateTemplate().saveOrUpdate(employee);
   }
   /* (non-Javadoc)
    * @see org.appfuse.dao.EmployeeDAO#removeEmployee(org.appfuse.model.DocumentId)
    */
   public void removeEmployee(DocumentId documentId) {
      Object employee = this.getHibernateTemplate().load(Employee.class,documentId);
      this.getHibernateTemplate().delete(employee);
   }   
}


The following is the documentId class that I use for the primary key with the "equals" method and the "hashCode" method.
Code:
public class DocumentId extends BaseObject{
   private String fiscalYear;
   private String documentNumber;

   public DocumentId(){}
   
   public DocumentId(String fiscalYear, String documentNumber){
      this.fiscalYear = fiscalYear;
      this.documentNumber = documentNumber;
   }

   /**
    * @return Returns the documentNumber.
    */
   public String getDocumentNumber() {
      return documentNumber;
   }
   /**
    * @return Returns the fiscalYear.
    */
   public String getFiscalYear() {
      return fiscalYear;
   }
   /**
    * @param documentNumber The documentNumber to set.
    */
   public void setDocumentNumber(String documentNumber) {
      this.documentNumber = documentNumber;
   }
   /**
    * @param fiscalYear The fiscalYear to set.
    */
   public void setFiscalYear(String fiscalYear) {
      this.fiscalYear = fiscalYear;
   }
   
   public boolean equals(Object o){
      if(this == o) return true;
      if(o == null) return false;
      if(!(o instanceof DocumentId)) return false;
      final DocumentId documentId = (DocumentId)o;
      if(!fiscalYear.equals((documentId.getFiscalYear()))) return false;
      if(!documentNumber.equals((documentId.getDocumentNumber()))) return false;
      return true;
   }
   
   public int hashCode() {
      return fiscalYear.hashCode();
   }
   
}


The following is the Employee class.
Code:
public class Employee {
   private DocumentId documentId;
   private WorkAddress workAddress;
   private Address homeAddress;
   private PhoneNumber homePhoneNumber;
   private PhoneNumber workPhoneNumber;
   private String middleName;
   private String suffix;
    private String firstName;
    private String lastName;
    private String gender;
    private int version;

    // empty constructor
    public Employee(){
    }
   
    /**
    * @return Returns the documentId.
    */
   public DocumentId getDocumentId() {
      return documentId;
   }
   /**
    * @param documentId The documentId to set.
    */
   public void setDocumentId(DocumentId documentId) {
      this.documentId = documentId;
   }
   /**
    * @return Returns the homeAddress.
    */
   public Address getHomeAddress() {
      return homeAddress;
   }
   /**
    * @param homeAddress The homeAddress to set.
    */
   public void setHomeAddress(Address homeAddress) {
      this.homeAddress = homeAddress;
   }
   /**
    * @return Returns the homePhoneNumber.
    */
   public PhoneNumber getHomePhoneNumber() {
      return homePhoneNumber;
   }
   /**
    * @param homePhoneNumber The homePhoneNumber to set.
    */
   public void setHomePhoneNumber(PhoneNumber homePhoneNumber) {
      this.homePhoneNumber = homePhoneNumber;
   }
   /**
    * @return Returns the middleName.
    */
   public String getMiddleName() {
      return middleName;
   }
   /**
    * @param middleName The middleName to set.
    */
   public void setMiddleName(String middleName) {
      this.middleName = middleName;
   }
   /**
    * @return Returns the suffix.
    */
   public String getSuffix() {
      return suffix;
   }
   /**
    * @param suffix The suffix to set.
    */
   public void setSuffix(String suffix) {
      this.suffix = suffix;
   }
   /**
    * @return Returns the workAddress.
    */
   public WorkAddress getWorkAddress() {
      return workAddress;
   }
   /**
    * @param workAddress The workAddress to set.
    */
   public void setWorkAddress(WorkAddress workAddress) {
      this.workAddress = workAddress;
   }
   /**
    * @return Returns the workPhoneNumber.
    */
   public PhoneNumber getWorkPhoneNumber() {
      return workPhoneNumber;
   }
   /**
    * @param workPhoneNumber The workPhoneNumber to set.
    */
   public void setWorkPhoneNumber(PhoneNumber workPhoneNumber) {
      this.workPhoneNumber = workPhoneNumber;
   }
   /**
    * @return Returns the firstName.
    */
   public String getFirstName() {
      return firstName;
   }
   /**
    * @param firstName The firstName to set.
    */
   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }
   /**
    * @return Returns the gender.
    */
   public String getGender() {
      return gender;
   }
   /**
    * @param gender The gender to set.
    */
   public void setGender(String gender) {
      this.gender = gender;
   }
   /**
    * @return Returns the lastName.
    */
   public String getLastName() {
      return lastName;
   }
   /**
    * @param lastName The lastName to set.
    */
   public void setLastName(String lastName) {
      this.lastName = lastName;
   }
   /**
    * @return Returns the version.
    */
   public int getVersion() {
      return version;
   }
   /**
    * @param version The version to set.
    */
   public void setVersion(int version) {
      this.version = version;
   }


The following is the entire Employee hibernate mapping:

Code:
<hibernate-mapping>
   <class name="org.appfuse.model.Employee" table="bbab20e">
      <composite-id name="documentId" class="org.appfuse.model.DocumentId">
         <key-property name="fiscalYear"
                    column="BBAB20E_CDFSYR"
                    type="string"/>
         <key-property name="documentNumber"
                    column="BBAB20E_NODOCU"
                    type="string"/>
      </composite-id>
      
      <version name="version" column="LOG_COUNTER" unsaved-value="null"/>
            
      <property name="firstName" column="BBAB20E_NMEMFS" />
      <property name="lastName" column="BBAB20E_NMEMLS" />   
      <property name="gender" column="BBAB20E_CDSEX"/>                  
      <property name="middleName" column="BBAB20E_NMEMMD" not-null="false"/>               
      <property name="suffix" column="BBAB20E_NMEMSF" not-null="false"/>

      <component
         name="homeAddress"
         class="org.appfuse.model.Address">
         <property name="street1"
                 column="BBAB20E_TXSTR1" not-null="false"/>
         <property name="street2"
                 column="BBAB20E_TXSTR2" not-null="false"/>       
         <property name="city"
                 column="BBAB20E_TXCTHM" not-null="false"/>
         <property name="state"
                 column="BBAB20E_TXSTHM" not-null="false"/>
         <property name="zipCode"
                 column="BBAB20E_CDZPHM" not-null="false"/>             
      </component>
      <component
         name="workAddress"
         class="org.appfuse.model.WorkAddress">   
         <component
            name="building"
            class="org.appfuse.model.Building">
            <property name="buildingNumber"
                 column="BBAB20E_NOBLDG" not-null="false"/> 
            <property name="buildingName"
                 column="BBAB20E_NMBLDG" not-null="false"/>                
         </component>
         <property name="floorNumber"
                 column="BBAB20E_NOFLOR" not-null="false"/>                
         <property name="roomNumber"
                 column="BBAB20E_NOROOM" not-null="false"/>
                
      </component>
      <component
         name="homePhoneNumber"
         class="org.appfuse.model.PhoneNumber">
         <property name="number"                
                 column="BBAB20E_NOPHHM" not-null="false"/>      
      </component>
      <component
         name="workPhoneNumber"
         class="org.appfuse.model.PhoneNumber">
         <property name="number"                
                 column="BBAB20E_NOPHOF" not-null="false"/>
      </component>
   </class>
</hibernate-mapping>



Now according to the Hibernate in Action book I should be able to call on saveOrUpdate to persiste my Employee object to the database. The one thing that I noticed in the book is the "unsaved-value" of the "version" mapping is set to "0" in the example. However after looking at the DTD there are only three options for "unsaved-value" for a "version" mapping and they are "null | negative | undefined ".
Thanks for your help and I hope the added code helps you to figure out what I am doing wrong here.
Thanks,
Christopher Kwiatkowski


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 08, 2004 9:56 am 
Regular
Regular

Joined: Tue Aug 26, 2003 7:53 pm
Posts: 66
Location: Lakeland, Florida USA
see http://forum.hibernate.org/viewtopic.ph ... ok+unsaved


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.