-->
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.  [ 5 posts ] 
Author Message
 Post subject: Insert au lieu de Update id generated merge Duplicate Entry
PostPosted: Wed Mar 19, 2008 4:47 am 
Newbie

Joined: Wed Mar 19, 2008 3:55 am
Posts: 3
Bonjour à tous,

je débute avec Hibernate 3.2.5ga Annotations3.3.0ga MySQL et les annotations et après plusieurs heures de recherche dans les forums et sur les sites je suis un peu bloqué.

Imaginez deux Objets Livre et Auteur reliés par une relation NaN coté Livre
Les livres et les auteurs rattachés sont contenus dans une liste.

Lors de la sauvegarde, j'ai une erreur
'Duplicate entry' car le programme essaie d'insérer un Objet Auteur avec la propriété name identique et un Id généré différent.

Si je supprime la contrainte @Column(unique=true) sur name.
Je n'ai plus d'erreur mais je n'ai plus unicité des Auteurs.

Comment corriger cela ? est ce les Annotations ?

Merci pour toute aide!!

Le code que j'ai utilisé est le suivant:

Code:
        for (final Livre livre : ListeLivres) {
          session.beginTransaction();
          session.merge(livre);
          session.getTransaction().commit();
        }


Code:
@Entity
public class Livre implements Serializable { 
.../...
@ManyToMany(targetEntity=com.package.Auteur.class,cascade=javax.persistence.CascadeType.ALL)
  public Set<Auteur> getAuteurs() {
    return auteurs;
  }
.../...
}

Code:
@Entity
public class Auteur implements Serializable {
   private static final long serialVersionUID = 1L;
   
   private Long id;
   
   @Id @GeneratedValue(strategy = GenerationType.AUTO)
   public Long getId () {
      return this.id;
   }
   public void setId (Long id) {
      this.id = id;
   }

  private String name;

  @Column(unique=true)
  public String getName () {
      return this.name;
  }
  public void setName (String name) {
      this.name = name;
  }
 
  public Auteur() {
  }

  public Auteur(String name) {
    this.name = name;
  }

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

  @Override
  public int hashCode() {
    int hash = 7;
    hash = 59 * hash + (this.name != null ? this.name.hashCode() : 0);
    return hash;
  }

  @Override
  public String toString() {
   if (this.name == null) return new String();
    return name;
  }


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 19, 2008 6:00 am 
Beginner
Beginner

Joined: Thu Jan 31, 2008 6:35 am
Posts: 27
Pas facile de repondre...

Si tu enleve le unique=true tu n'as plus d'erreur mais as tu des doublons dans ta base ? c'est as dire qu'a chaque merge au lieu de faire un update il créé un nouvel objet.

Pour ton merge ton objet livre a-t-il bien le bon id ?

Sinon au niveau code, pour gagner en perf je te conseil :
Code:
        session.beginTransaction();
        for (final Livre livre : ListeLivres) {
          session.merge(livre);
        }
        session.getTransaction().commit();

Attention fonctionnellement ca ne fait pas la meme chose, mais c'est beaucoup plus rapide, as toi de voir...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 19, 2008 6:21 am 
Newbie

Joined: Wed Mar 19, 2008 3:55 am
Posts: 3
sliard wrote:
Si tu enleve le unique=true tu n'as plus d'erreur mais as tu des doublons dans ta base ?

Oui des doublons d'auteurs, pas de livres
sliard wrote:
c'est as dire qu'a chaque merge au lieu de faire un update il créé un nouvel objet.

Oui car il ne rattache pas l'auteur (sans id) à un auteur existant avec id
sliard wrote:
Pour ton merge ton objet livre a-t-il bien le bon id ?

Oui l'id livre est fixé et fourni par contre l'id auteur est auto-incrémenté.

Quote:
Sinon au niveau code, pour gagner en perf je te conseil :
Code:
        session.beginTransaction();
        for (final Livre livre : ListeLivres) {
          session.merge(livre);
        }
        session.getTransaction().commit();


Attention fonctionnellement ca ne fait pas la meme chose, mais c'est beaucoup plus rapide, as toi de voir...

Oui bien sûr je change dès que les updates se feront correctement ;-)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 19, 2008 7:12 am 
Beginner
Beginner

Joined: Thu Jan 31, 2008 6:35 am
Posts: 27
Donc c'est un comportement logique :)

Si tu ne lui donne pas l'id de l'auteur il ne peut pas le retrouver et donc il essaie d'en ajouter un.

Il faut soit indiquer l'id de l'auteur avant ou ajouter le nom de l'auteur comme clé de la classe (voir une clé composite avec l'id et ne nom).
Mais la désole, je n'ai jamais fait ça.


Autre solution... avant le merge tu fais un findByName de l'auteur et tu change la référence.
Code:
        session.beginTransaction();
        for (final Livre livre : ListeLivres) {

          Collection<Auteur> realAuteur = new ArrayList<Auteur>();
          for (final Auteur auteur : livre.getAuteur()) {
            Criteria crit = session.createCriteria(Livre.class);
            crit.add(Restrictions.eq("name", auteur.getName()));
            crit.setCacheable(true);

            Collection res = crit.list();         
            if(res.size() > 0) {
              //Auteur existant... on ajoute
              // pas beau ! a refaire ;)
              realAuteur.add(crit.list().iterator().next());
            } else
              // Nouvel auteur il faudra le creer
               realAuteur.add(auteur);
            }
          }
          livre.setAuteur(realAuteur);

          session.merge(livre);
        }
        session.getTransaction().commit();

Code ecrit rapidement... je ne garanti pas qu'il compile :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 19, 2008 8:27 am 
Newbie

Joined: Wed Mar 19, 2008 3:55 am
Posts: 3
sliard wrote:
Donc c'est un comportement logique :)

Oui c'est la logique du code actuel.

Quote:
Si tu ne lui donne pas l'id de l'auteur il ne peut pas le retrouver et donc il essaie d'en ajouter un.


Ce que je cherche c'est une annotation ou code qui donne la logique suivante: si pour l'Objet Auteur le name est identique l'id doit être id est identique. C'est un peu pour cela que la méthode equals de Auteur ne concerne que la proprieté name.

Quote:
Il faut soit indiquer l'id de l'auteur avant ou ajouter le nom de l'auteur comme clé de la classe (voir une clé composite avec l'id et ne nom).
Mais la désole, je n'ai jamais fait ça.

Qui sait peut être quelqu'un d'autre pourra contribuer

Quote:
Autre solution... avant le merge tu fais un findByName de l'auteur et tu change la référence.

Oui c'est déjà une bonne solution qui va me débloquer un peu.
Cool ;-)


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