2009-08-14 6 views
1

J'ai deux entités comme les suivantes:Shound J'évite d'utiliser mappedBy pour garder mon application stable?

@Entity 
public class Trip { 

    @OneToMany(mappedBy = "trip", fetch = FetchType.LAZY) 
    private Set<Job> jobs = new HashSet<Job>(); 

} 

@Entity 
public class Job { 

    @ManyToOne(fetch = FetchType.LAZY) 
    private Trip trip; 

} 

Le problème est que la relation mappedBy se comporte différemment dans des circonstances différentes. Voici un exemple

EntityManager em1 = unit.createEntityManager(); 
    EntityManager em2 = unit.createEntityManager(); 

    // One EM starts transaction and stores a trip 
    em1.getTransaction().begin(); 

    Trip trip = new Trip(); 
    em1.persist(trip); 

    Long tripId = trip.getId(); 

    assertThat(tripId).isPositive(); 

    em1.getTransaction().commit(); 

    // Then em2 starts different transaction 
    em2.getTransaction().begin(); 

    // Looking up for the trip through clean em (cache is empty) 
    Trip em2Trip = em2.find(Trip.class, tripId); 

    Job job = new Job(); 
    job.setTrip(em2Trip); 

    em2.persist(job); 

    // The em2Trip should not be updated 

    assertThat(em2Trip.getJobs()).hasSize(1); 

    em2.getTransaction().commit(); 

    em1.getTransaction().begin(); 

    Trip em1Trip = em1.find(Trip.class, tripId); 

    // fails here 
    assertThat(em1Trip.getJobs()).hasSize(1); 

    em1.getTransaction().commit(); 

Le code ci-dessus montre que si une entité est déjà chargée dans le cache du gestionnaire d'entités, le getter de la relation mappedBy peut retourner des résultats incorrects.

J'ai une preuve que cela ne fonctionne pas non plus sous JBoss. Le code suivant se comporte différemment selon le gestionnaire d'entité utilisé. Le résultat est imprévisible. Est-ce que cela signifie que le mappedBy rend automatiquement l'application buggée dès qu'elle est introduite et utilisée?

P.S. Je n'essaie pas d'abuser d'Hibernate. Je veux seulement savoir si quelqu'un a fait face à un tel problème et comment y ont-ils fait face

+0

S'il vous plaît modifier votre question et essayer de garder son objectif. Personne n'aime lire les diatribes. –

+0

Est-ce mieux maintenant? – artemb

Répondre

2

Comportement que vous décrivez a absolument rien à faire avec des associations; vous obtiendriez exactement les mêmes résultats si vous essayiez juste de lire/mettre à jour un simple POJO de deux gestionnaires d'entités. Une fois que votre entité est associée au contexte de persistance, elle ne sera PAS automatiquement actualisée à partir de la base de données. C'est un comportement documenté - et dans la grande majorité des cas, c'est un comportement DÉSIRÉ.

En ce qui concerne « le maintien de votre application stable » va:

  1. instances EntityManager correspondent directement aux sessions Hibernate et ne devraient donc pas être détenus pendant des périodes de temps prolongées. Si vous réécrivez votre code ci-dessus pour utiliser une nouvelle instance d'EntityManager (em3) au lieu de réutiliser em1, votre problème disparaîtra.
  2. EntityManager dispose d'une méthode refresh() que vous pouvez appeler pour recharger l'état de l'entité à partir de la base de données.
  3. EntityManager a une méthode clear() qui effacera complètement le contexte de persistance, évitant ainsi ce problème. Utilisez-le avec parcimonie et prudence, cependant - invoquer clear() sans flush() jettera toutes les mises à jour en attente.
+0

C'est vrai, les attributs simples ne sont pas mis à jour non plus! Merci de l'avoir signalé. – artemb

1

L'utilisation de mappedBy (c'est-à-dire des associations bidirectionnelles) n'est pas boguée ou incohérente. Il est cependant difficile à configurer, et vous devez faire très attention à la façon dont vous l'utilisez - ce n'est pas une solution miracle, et si vous ne suivez pas les directives de programmation, vous pouvez mettre vos entités dans un état incohérent. J'ai tendance à les éviter pour cette raison; Je les utilise seulement si vraiment besoin d'associations bidirectionnelles, dans mon expérience, c'est très rare.

+1

Excellente réponse, et un changement rafraîchissant pour voir des conseils contre bidirectionnel. La référence Hibernate utilise trop d'argument par assertion. –

Questions connexes