2010-11-19 23 views
3

J'ai un test d'intégration d'un DAO dans lequel j'utilise un EntityManager partagé (via Spring, en utilisant SharedEntityManagerCreator). La classe de test est marquée comme @Transactional, de même que la méthode DAO en cours de test.JPA: EntityManager.find() renvoie-t-il toujours la même référence d'objet pour la même clé?

Dans la classe d'essai et le DAO je retreiving une entité utilisateur comme suit:

User user = em.find(User.class, "test"); 

Dans la configuration de mon test, je l'ai modifié l'objet utilisateur, mais je ne voyais pas la modification dans le DAO lorsque le test est venu à courir. Il s'est avéré que les deux références ne se référaient pas au même objet; Je l'ai prouvé dans ma classe de test en utilisant:

System.out.println("User objects equal = " + (user == dao.getUser())); 

Ceci a été imprimé faux. Je m'attendais à ce que chaque appel à un EntityManager utilisant la même clé renvoie la même référence d'objet, et a été surpris (et un peu alarmé!) De découvrir que ce n'était pas le cas. Quelqu'un peut-il nous éclairer à ce sujet? J'ai refacturé mon code donc ce n'est pas vraiment un problème (le DAO ne devrait pas avoir l'objet User dedans de toute façon) mais j'aimerais quand même mieux le comprendre.

Merci!

Java 1.6u22, Toplink Essentials 2.0.1, Spring 2.5.6

Répondre

5

find() renvoie la même instance dans un contexte de contexte de persistance.

Dans le cas de partage EntityManager (géré par conteneur contexte de persistance scope transaction, en termes JPA Spec) cycle de vie du contexte de persistance est lié à la transaction, donc find() retourne la même instance lorsqu'il est appelé à partir de la même transaction. Je suppose que dans votre cas, la configuration de votre test ne se fait pas dans la même transaction qu'une méthode de test, donc find() produit différentes instances.

+1

axtavt est correct. Lorsque EntityManager est fermé, le contexte de persistance associé à celui-ci est récupéré. Si votre instance de EntityManager est fournie automatiquement par le conteneur avec la transaction, alors vos appels à em.find() retourneront toujours le même objet physique pour la même clé primaire tant que la même transaction (et EntityManager) sont toujours ouvrir. Si vous avez besoin d'un EntityManager avec une durée de vie plus longue, vous avez la possibilité d'utiliser un EntityManager géré par l'application au lieu d'un Entité Manager géré par le conteneur, mais avec un travail supplémentaire. –

+0

Je vois, merci pour vos réponses. Je suis sûr qu'il n'y a qu'une seule transaction partagée par mon test et mon dao, car les méthodes annotées @Before et @After sont incluses par l'annotation @Transactional; Les journaux Toplink affichent également une seule transaction. Donc je suppose que je ne dois pas avoir le même EntityManager dans la classe de test et le DAO. Existe-t-il un moyen de savoir si deux EntityManagers sont identiques? Je sais que le EntityManager partagé que Spring me donne est en fait un proxy qui délègue les appels, donc je ne vois pas de manière évidente de vérifier. – Conan

+0

@Conan: J'ai vérifié et découvert que les méthodes '@ Before' /' @ After' sont réellement exécutées dans la même transaction que '@ Test', donc' em.find() 'retourne les mêmes instances. Peut-être que votre problème a une autre cause. Vous pouvez enregistrer 'TransactionSynchronizationManager.getCurrentTransactionName()' pour vérifier l'identité de la transaction. – axtavt

0

Non, il ne fonctionne pas. De toute façon, vous devriez compter sur l'égalité des objets au lieu de l'identité. Remplacer la méthode égale.