-->
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: Detached entities : concurrent merge issue
PostPosted: Mon Aug 06, 2007 5:10 am 
Newbie

Joined: Fri May 11, 2007 10:54 am
Posts: 7
Hello,

I am working with the detached entities pattern, and I am facing a concurrent merge issue.
I reproduced it with the small following example.
A class 'A' has two children b1 and b2 :

Code:
public class A
{
   private Long id;
   private Integer version;
   private B b1;
   private B b2;
   
   public B getB1() { return b1; }
   public void setB1(B b1) { this.b1 = b1;   }

   public B getB2() { return b2;}
   public void setB2(B b2) { this.b2 = b2;   }

   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }

   public Integer getVersion() { return version; }

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


Code:
public class B {
   private Long id;
   private Integer version;
   private String description;
   
   public String getDescription() { return description; }
   public void setDescription(String description) { this.description = description; }

   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }

   public Integer getVersion() { return version; }

   public void setVersion(Integer version) { this.version = version; }
   
   public boolean equals(Object obj) { ... }
   public int hashCode() { ... }
}


The mapping files are very simple :
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="fr.test.domain">
   <class name="A" table="A">
      <id name="id" column="A_ID">
         <generator class="increment" />
      </id>
      <version name="version" column="VERSION">
      </version>
      <many-to-one name="b1" cascade="all" class="fr.test.domain.B" />
      <many-to-one name="b2" cascade="all" class="fr.test.domain.B" />
   </class>
</hibernate-mapping>


Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="fr.test.domain">
  <class name="B" table="B">
      <id name="id" column="B_ID">
         <generator class="increment" />
      </id>
      <version name="version" column="VERSION">
      </version>
      <property name="description" column="DESCRIPTION"/>
  </class>
</hibernate-mapping>



When the user sets a detached entity to b1, if this object points to the same entity than b2 _ which is a possible business case _
I cannot save the A instance anymore :
- if I use session.saveOrUpdate(a), a NonUniqueObjectException is thrown
- if I use session.merge(a), no exception is thrown but b1 modification is lost !

Code:
public class Test extends TestCase
{
   private A a;
   
        protected void setUp() throws Exception
   {
        //init
        a = init();
       
        //load B1
        B newB1 = loadB(a.getB2().getId());
        newB1.setDescription("b1");
        a.setB1(newB1);
   }
   
   public void testSaveOrUpdate()
   {
      assertNotNull(a);
      
   //   throws [b]NonUniqueObjectException[/b]
   //
      saveA(a);
   }
   
   public void testMerge()
   {
        assertNotNull(a);
      
        // Works but...
        a = mergeA(a);

        // .... [b]b1 modification is lost[/b]
        assertEquals("b1", a.getB1().getDescription());
   }
   
   //-------------------------------------------------------------------------
   // Internal methods
   //-------------------------------------------------------------------------
   protected A init() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();

        A a = new A();
        B b = new B();
        b.setDescription("b");
        a.setB1(b);
        a.setB2(b);
        session.save(a);
      
        tx.commit();
        session.close();
        return a;
   }

   protected void saveA(A a)
   {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
       
        session.saveOrUpdate(a);
       
        tx.commit();
        session.close();
   }
   
   protected A mergeA(A a)
   {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
      
        A result = (A) session.merge(a);
       
        tx.commit();
        session.close();
       
        return result;
   }
   
   protected B loadB(Long id)
   {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();

        B b = (B)session.get(B.class, id);
   
        tx.commit();
        session.close();
        return b;
   }
}


I would have expected Hibernate to merge correctly, or at least to throw an exception notifying that it cannot merge the b1 object since it has been modified...

Does anyone knows how to solve this problem ?
Best Regards
Bruno


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 28, 2007 3:02 am 
Newbie

Joined: Tue Aug 28, 2007 2:57 am
Posts: 2
up :)


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.