-->
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.  [ 2 posts ] 
Author Message
 Post subject: problem cascading merge across associations
PostPosted: Thu Mar 08, 2007 7:25 pm 
Newbie

Joined: Tue Aug 29, 2006 2:10 pm
Posts: 11
I'm getting an OptimisticLockException that makes no sense to me when trying to cascade merge across an explicit association entity. My annotations may be screwed up (I'm fairly new to JPA). Here's the code for my entities:

Code:
package com.foo.persist;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@Table(name="RPR_ROOT_PARENT")
public class RootParent {
   
   private Long internalId;
   
   private String rootParentId;
   
   private Integer version;
   
   private Set<Association> associationSet;
   
   @OneToMany(mappedBy="rootParent", cascade={CascadeType.PERSIST, CascadeType.MERGE})
   public Set<Association> getAssociationSet() {
      return associationSet;
   }

   public void setAssociationSet(Set<Association> associationSet) {
      this.associationSet = associationSet;
   }

   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   @Column(name="RPR_UID")
   public Long getInternalId() {
      return internalId;
   }

   public void setInternalId(Long internalId) {
      this.internalId = internalId;
   }

   @Column(name="RPR_ID")
   public String getRootParentId() {
      return rootParentId;
   }

   public void setRootParentId(String rootParentId) {
      this.rootParentId = rootParentId;
   }

   @Version
   @Column(name="RPR_VERSION")
   public Integer getVersion() {
      return version;
   }

   public void setVersion(Integer version) {
      this.version = version;
   }

   @Override
   public int hashCode() {
      final int PRIME = 31;
      int result = 1;
      result = PRIME * result + ((rootParentId == null) ? 0 : rootParentId.hashCode());
      return result;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      final RootParent other = (RootParent) obj;
      if (rootParentId == null) {
         if (other.rootParentId != null)
            return false;
      } else if (!rootParentId.equals(other.rootParentId))
         return false;
      return true;
   }
}

package com.foo.persist;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@IdClass(AssociationPK.class)
@Table(name="ASC_ASSOCIATION")
public class Association implements Serializable {
   
   /**
    *
    */
   private static final long serialVersionUID = -3746181614360357763L;
   
   private long rootParentUid;
   
   private RootParent rootParent;
   
   private long leafParentUid;
   
   private LeafParent leafParent;
   
   private Integer version;
   
   @Id
   @Column(name="ASC_LPR_UID", updatable=false, insertable=false)
   public long getLeafParentUid() {
      return leafParentUid;
   }

   public void setLeafParentUid(long leafParentUid) {
      this.leafParentUid = leafParentUid;
   }

   @Id
   @Column(name="ASC_RPR_UID", updatable=false, insertable=false)
   public long getRootParentUid() {
      return rootParentUid;
   }

   public void setRootParentUid(long rootParentUid) {
      this.rootParentUid = rootParentUid;
   }
   
   @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
   @JoinColumn(name="ASC_LPR_UID")
   public LeafParent getLeafParent() {
      return leafParent;
   }

   public void setLeafParent(LeafParent leafParent) {
      this.leafParent = leafParent;
   }

   @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
   @JoinColumn(name="ASC_RPR_UID")
   public RootParent getRootParent() {
      return rootParent;
   }

   public void setRootParent(RootParent rootParent) {
      this.rootParent = rootParent;
   }
   
   @Version
   @Column(name="ASC_VERSION")
   public Integer getVersion() {
      return version;
   }

   public void setVersion(Integer version) {
      this.version = version;
   }

   @Override
   public int hashCode() {
      final int PRIME = 31;
      int result = 1;
      result = PRIME * result + ((leafParent == null) ? 0 : leafParent.hashCode());
      result = PRIME * result + ((rootParent == null) ? 0 : rootParent.hashCode());
      return result;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      final Association other = (Association) obj;
      if (leafParent == null) {
         if (other.leafParent != null)
            return false;
      } else if (!leafParent.equals(other.leafParent))
         return false;
      if (rootParent == null) {
         if (other.rootParent != null)
            return false;
      } else if (!rootParent.equals(other.rootParent))
         return false;
      return true;
   }

   
}

package com.foo.persist;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Id;

@SuppressWarnings("unused")
public class AssociationPK implements Serializable {

   /**
    *
    */
   private static final long serialVersionUID = 1L;

   private long leafParentUid;
   
   private long rootParentUid;
   
   public AssociationPK() {}
   
   public AssociationPK(long leafParentUid, long rootParentUid) {
      this.leafParentUid = leafParentUid;
      this.rootParentUid = rootParentUid;
   }

   public long getLeafParentUid() {
      return leafParentUid;
   }

   public void setLeafParentUid(long leafParentUid) {
      this.leafParentUid = leafParentUid;
   }

   public long getRootParentUid() {
      return rootParentUid;
   }

   public void setRootParentUid(long rootParentUid) {
      this.rootParentUid = rootParentUid;
   }
}

package com.foo.persist;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@Table(name="LPR_LEAF_PARENT")
public class LeafParent {
   
   private Long internalId;
   
   private String leafParentId;
   
   private Integer version;
   
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   @Column(name="LPR_UID")
   public Long getInternalId() {
      return internalId;
   }

   public void setInternalId(Long internalId) {
      this.internalId = internalId;
   }

   @Column(name="LPR_ID")
   public String getLeafParentId() {
      return leafParentId;
   }

   public void setLeafParentId(String leafParentId) {
      this.leafParentId = leafParentId;
   }

   @Version
   @Column(name="LPR_VERSION")
   public Integer getVersion() {
      return version;
   }

   public void setVersion(Integer version) {
      this.version = version;
   }

   @Override
   public int hashCode() {
      final int PRIME = 31;
      int result = 1;
      result = PRIME * result + ((leafParentId == null) ? 0 : leafParentId.hashCode());
      return result;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      final LeafParent other = (LeafParent) obj;
      if (leafParentId == null) {
         if (other.leafParentId != null)
            return false;
      } else if (!leafParentId.equals(other.leafParentId))
         return false;
      return true;
   }

   
}



And here's my unit test:
Code:
package com.foo.test;

import java.util.HashSet;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import junit.framework.TestCase;

import com.foo.persist.Association;
import com.foo.persist.LeafParent;
import com.foo.persist.RootParent;

public class JpaTest extends TestCase {
   
   private static EntityManagerFactory emf;
    private static EntityManager em;
   
    private static boolean init = false;
   
    @Override
   protected void setUp() throws Exception {
       if (!init) {
          // Create EntityManagerFactory for persistent unit named "pu1"
            // to be used in this test
            emf = Persistence.createEntityManagerFactory("pu1");
           
            // Create a new EntityManager
            em = emf.createEntityManager();
           
            init = true;
       }
   }

    private void doMerge(Object pObj) {
      em.getTransaction().begin();
      em.merge(pObj);
      em.getTransaction().commit();
   }
   
    private void doPersist(Object pObj) {
       em.getTransaction().begin();
       em.persist(pObj);
       em.getTransaction().commit();
    }
   
    public void testUpdateRootParentWithTransientLeafParent() throws Exception {
      Query q = em.createQuery("select r from RootParent r where r.rootParentId = 'RPR1'");
      RootParent r = (RootParent)q.getSingleResult();
      LeafParent l = new LeafParent();
      l.setLeafParentId("TRANSIENTLEAF");
      Association a = new Association();
      a.setLeafParent(l);
      a.setRootParent(r);
      r.getAssociationSet().add(a);
      doMerge(r);
    }
}



I'm getting the following stacktrace from testUpdateRootParentWithTransientLeafParent:

javax.persistence.OptimisticLockException
at org.hibernate.ejb.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:642)
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:599)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:236)
at com.foo.test.JpaTest.doMerge(JpaTest.java:39)
at com.foo.test.JpaTest.testUpdateRootParentWithTransientLeafParent(JpaTest.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:228)
at junit.framework.TestSuite.run(TestSuite.java:223)
at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:35)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.foo.persist.Association#com.foo.persist.AssociationPK@1bdbfec]
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:261)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:120)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:687)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:245)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:407)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:152)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:126)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:227)
... 21 more

I'm testing this specifically because I have multiple use cases where I have an association entity with extra information in it, but the primary key is a composite key, and I can't use a surrogate key because it's a legacy db that I'm not allowed to change.

Any help here?

Thanks, Greg


Top
 Profile  
 
 Post subject: more info
PostPosted: Thu Mar 08, 2007 7:27 pm 
Newbie

Joined: Tue Aug 29, 2006 2:10 pm
Posts: 11
forgot to post persistence.xml:

Code:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
   version="1.0">
   <persistence-unit name="pu1">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>com.foo.persist.Association</class>
      <class>com.foo.persist.AssociationPK</class>
      <class>com.foo.persist.LeafParent</class>
      <class>com.foo.persist.RootParent</class>
      <properties>
      
         <property name="hibernate.hbm2ddl.auto" value="create" />
         <property name="hibernate.dialect"
            value="org.hibernate.dialect.DerbyDialect" />
         <property name="hibernate.connection.driver_class"
            value="org.apache.derby.jdbc.EmbeddedDriver" />
         <property name="hibernate.connection.username" value="" />
         <property name="hibernate.connection.password" value="" />
         <property name="hibernate.connection.url"
            value="jdbc:derby:data\testdb;create=true" />
         <property name="hibernate.max_fetch_depth" value="3" />
         <property name="hibernate.show_sql" value="false" />
         
      </properties>
   </persistence-unit>
</persistence>



Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 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.