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.  [ 1 post ] 
Author Message
 Post subject: Problème de merge concurrent
PostPosted: Tue Aug 07, 2007 5:04 am 
Newbie

Joined: Fri May 11, 2007 10:54 am
Posts: 7
Bonjour à tous,

Je travaille avec des objets détachés, et j'ai un problème avec la fonction "merge".
Celui-ci est reproduit avec l'exemple suivant : la classe A a deux attributs, b1 et b2 de type B :

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() { ... }
}


Les fichiers de mapping sont tout aussi 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>


Quand l'utilisateur remplace b1 ar une entité détachée, si cette dernière pointe sur le même enregistrement que b2 (ce qui est un
cas d'utilisation normal dans notre application), la sauvegarde de A devient alors impossible :
- avec session.saveOrUpdate(a), je reçois une exception NonUniqueObjectException car les deux objets détachés b1 et b2 pointent sur la même entité
- avec session.merge(a), je n'ai pas d'exception mais les modifications de b1 sont perdues !

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 NonUniqueObjectException
   //
      saveA(a);
   }
   
   public void testMerge()
   {
      assertNotNull(a);
      
           // Works but...
      a = mergeA(a);

                // .... b1 modification is lost
      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;
   }
}


J'avoue que j'aurais attendu qu'Hibernate fusionne correctement les deux objets, ou au minimum qu'il envoie une exception signifiant un conflit entre les deux entités à fusionner.

Est-ce que quelqu'un sait s'il existe un moyen "natif" de solutionner ce problème ?

Bruno


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

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.