IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Hibernate Java Discussion :

Problème de mise à jour de l'ordre sur une table d'association (@OrderColumn + @JoinTable)


Sujet :

Hibernate Java

  1. #1
    Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut Problème de mise à jour de l'ordre sur une table d'association (@OrderColumn + @JoinTable)
    Bonjour,

    Dans l'exemple suivant, je souhaite conserver l'ordre des loisirs.

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Entity
    @Table(name = "personne")
    public class Personne {
     
    	@OneToMany(fetch = FetchType.LAZY)
    	@JoinTable(name = "loisir_personne", joinColumns = {@JoinColumn(name = "personne", nullable = false, updatable = false)}, inverseJoinColumns = {@JoinColumn(name = "loisir", nullable = false, updatable = false)})
    	@OrderColumn(name = "idx")
    	private List<Loisir> loisirs = new ArrayList<Loisir>(0);
     
    }

    L'enregistrement et la récupération marche bien, mais si je change l'ordre de la liste je reçois un message de violation de clé primaire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ERROR: duplicate key value violates unique constraint "pk_loisir_personne"  DétailÂ*: Key (personne, loisir)=(11900, 4) already exists.
    Dans ce cas Hibernate essaye de faire un update:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Hibernate: update madb.loisir_personne set loisir=? where personne=? and idx=?
    Alors que sans le @OrderColumn, il supprime puis fait un insert (dans ce cas je n'ai pas de message d'erreur évidemment)

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    @OneToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "loisir_personne", joinColumns = {@JoinColumn(name = "personne", nullable = false, updatable = false)}, inverseJoinColumns = {@JoinColumn(name = "loisir", nullable = false, updatable = false)})
    //@OrderColumn(name = "idx")
    private List<Loisir> loisirs = new ArrayList<Loisir>(0);

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Hibernate: delete from madb.loisir_personne where personne=?
    Hibernate: insert into madb.loisir_personne (personne, loisir) values (?, ?)
    Hibernate: insert into madb.loisir_personne (personne, loisir) values (?, ?)
    Hibernate: insert into madb.loisir_personne (personne, loisir) values (?, ?)
    Est-ce que quelqu'un aurait une solution?
    Merci.


    SQL:
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    CREATE TABLE madb.loisir_personne
    (
      personne numeric(10,0) NOT NULL,
      loisir numeric(5,0) NOT NULL,
      idx numeric(2,0) NOT NULL DEFAULT 0,
      CONSTRAINT pk_loisir_personne PRIMARY KEY (personne, loisir),
      CONSTRAINT fk_loispers_pers FOREIGN KEY (personne)
          REFERENCES madb.personne (id) MATCH SIMPLE
          ON UPDATE NO ACTION ON DELETE RESTRICT,
      CONSTRAINT fk_loispers_lois FOREIGN KEY (loisir)
          REFERENCES madb.loisir (id) MATCH SIMPLE
          ON UPDATE RESTRICT ON DELETE RESTRICT
    )

    -----------------------
    DB: PostgreSQL v 9.2
    Hibernate v 4.2.1.Final

  2. #2
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut
    salut
    peux-tu nous montrer comment est ce que tu changes l´ordre, ainsi que le contenu avant le changement de l´ordre.

    Eric

  3. #3
    Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Bonjour jeffray03
    Merci de t'intéresser à mon problème.

    Voici le contenu avant changement:

    personne loisir idx
    11900 2 0
    11900 4 1
    11900 3 2

    Sur l'IHM (gwt), l'utilisateur devrait pouvoir réordonner ses loisirs (en fonction de ses préférences) via Drag & Drop ou autre

    Ce que je fais quand un utilisateur envoie une nouvelle list:

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    // personneDto vient de la partie client (GWT)
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Boolean updatePersonne(PersonneDto personneDto) throws Exception {
          Personne personne = personneDao.findById(personneDto.getId());
          List<Loisir> loisirs = loisirDao.findByIds(personneDto.getLoisirs());
          personne.getLoisirs().clear();
          personne.getLoisirs().addAll(loisirs);
          personneDao.update(personne);
    }
    loisirDao.findByIds() étant:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @Override
    public Collection<T> findByIds(List<Long> lIds) throws Exception {
    	if (lIds==null||lIds.isEmpty()) return null;
    	Collection<T> lst = findByIdsUnsorted(lIds);
    	Map<Integer, T> map = new TreeMap<>();
    	for (T val : lst){
    		map.put(lIds.indexOf(val.getId()), val);
    	}
    	return new ArrayList<>(map.values());
    }
     
    private Collection<T> findByIdsUnsorted(Collection<Long> lIds) throws Exception {
    	logger.debug("find By Ids {}", clazz.getName());
    	if (lIds==null||lIds.isEmpty()) return null;
    	try {
    		DetachedCriteria criteria = DetachedCriteria.forClass(clazz);
    		criteria.add(Restrictions.in("id", lIds));
    			List<T> lst = findByCriteria(criteria);
    		return lst;
    	} catch (RuntimeException re) {
    		logger.error("find by property name failed", re);
    		throw re;
    	}
    }
    personneDao.update() étant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    @Override
    public T update(final T entity) {
    	Preconditions.checkNotNull(entity);
    	return getEntityManager().merge(entity);
    }

    Résultat désiré:

    personne loisir idx
    11900 2 0
    11900 4 2
    11900 3 1

  4. #4
    Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    En faisant un flush() entre clear() et addAll() ça marche:



    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    // personneDto vient de la partie client (GWT)
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Boolean updatePersonne(PersonneDto personneDto) throws Exception {
          Personne personne = personneDao.findById(personneDto.getId());
          List<Loisir> loisirs = loisirDao.findByIds(personneDto.getLoisirs());
          personne.getLoisirs().clear();
     
          personneDao.getEntityManager().flush();
     
          personne.getLoisirs().addAll(loisirs);
          personneDao.update(personne);
    }


    Je n'ai pas l'impression que cela soit une "best practice" et je ne comprends pas le besoin d'utiliser flush() entre les 2 instructions.
    PS: j'ai essayé cela par hasard (ou par désespoir) après avoir lu le post: https://forum.hibernate.org/viewtopi...48410#p2448410


    Est-ce que quelqu'un peu m'éclairer sur ce point?

    Merci

  5. #5
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut
    salut,
    en faisant le flush(), le changement s´effectue au niveau de la base de données, c´est a dire une sorte de commit,
    et c´est pour cela que la derniere operation marche, car elle n´est plus presente dans la base de données.


    Eric

  6. #6
    Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Salut Eric et merci pour ton explication.
    Je vais donc utiliser flush.

  7. #7
    Membre chevronné Avatar de jeffray03
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2008
    Messages
    1 501
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 501
    Points : 2 120
    Points
    2 120
    Par défaut
    salut, pour rappel,
    si tu veux que cela marche comme tu veux?
    il faudra creer ta table comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    CREATE TABLE madb.loisir_personne
    (
      personne numeric(10,0) NOT NULL,
      loisir numeric(5,0) NOT NULL,
      idx numeric(2,0) NOT NULL DEFAULT 0,
      CONSTRAINT pk_loisir_personne PRIMARY KEY (personne, loisir, idx_numeric),
      CONSTRAINT fk_loispers_pers FOREIGN KEY (personne)
          REFERENCES madb.personne (id) MATCH SIMPLE
          ON UPDATE NO ACTION ON DELETE RESTRICT,
      CONSTRAINT fk_loispers_lois FOREIGN KEY (loisir)
          REFERENCES madb.loisir (id) MATCH SIMPLE
          ON UPDATE RESTRICT ON DELETE RESTRICT
    )
    et tu veras que ton premier code marchera sans souci.

    Eric

  8. #8
    Candidat au Club
    Inscrit en
    Mars 2009
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 5
    Points : 3
    Points
    3
    Par défaut
    Excellent, et si simple.
    Merci Eric

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Mise à jour des statistiques Impossible sur une table volumineuse
    Par joujousagem2006 dans le forum Administration
    Réponses: 21
    Dernier message: 26/05/2014, 05h58
  2. Réponses: 5
    Dernier message: 12/05/2009, 15h57
  3. [XL-2003] Faire mise à jour fichier excel stocké sur une page web
    Par fidecourt dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 09/04/2009, 17h12
  4. Mise a jour d'un index sur une table de 22 colonnes
    Par loupin dans le forum Oracle
    Réponses: 4
    Dernier message: 09/08/2007, 07h26
  5. Réponses: 1
    Dernier message: 24/04/2006, 16h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo