Pourquoi un objet trouvé par id dans JPA, mais pas par une requête JPQL?
Question
J'ai un test JUnit 4 avec l'annotation @Transactional
printemps qui sauve un objet, puis tente de le trouver. Le cas de test passe lorsque j'utilise cette implémentation:
@Override
public EventSummary findEventSummaryById(Integer id) {
return em.find(EventSummary.class, id);
}
Il échoue quand j'utilise cette mise en œuvre (et changement qui méthode que je appel dans le cas de test):
@Override
public EventSummary findEventSummary(Integer id) {
Query query = em.createQuery("select es from EventSummary as es where es.id = :id");
query.setParameter("id", id);
EventSummary result = (EventSummary) query.getSingleResult();
return result;
}
La solution
Si vous utilisez le mode de rinçage par défaut (AUTO
) et si vous exécutez votre requête dans une transaction, les garanties de spécification JPA qu'une requête ne renvoie des données périmées ou incorrectes:
3.6.2 Requêtes et FlushMode
Le réglage du mode de rinçage affecte la résultat d'une requête comme suit.
Lorsque les requêtes sont exécutées dans un transaction, si
FlushModeType.AUTO
est défini, ou si l'objet de laQuery
réglage du mode de rinçage pour la persistance contexte estAUTO
(par défaut) et réglage du mode de chasse n'a pas été spécifié pour l'objetQuery
, la fournisseur de persistance est responsable de veiller à ce que toutes les mises à jour de la état de toutes les entités du contexte de persistance qui pourrait potentiellement affecter le résultat de la requête sont visibles pour le traitement de la requête. Le fournisseur de persistance la mise en œuvre peut y parvenir en chasse ces entités à la base de données ou par d'autres moyens. SiFlushModeType.COMMIT
est défini, le effet des mises à jour faite aux entités le contexte de persistance sur les requêtes est non spécifiée.public enum FlushModeType { COMMIT, AUTO }
S'il n'y a pas de transaction active, la fournisseur de persistance ne doit pas rincer à la base de données.
En supposant que vous utilisez AUTO
, vérifiez le côté transactionnel.
Autres conseils
entité Тhe est dans la session en cours (gestionnaire d'entités) - il est dans un état persistant, en attendant d'être vidées. La méthode get vérifie d'abord le contenu de la session, et si on ne trouve pas à tour de rôle à la base de données sous-jacente. Dans votre cas, l'entité vient d'être enregistrée dans la même session, il se trouve et est revenu.
Mise à jour: il est apparu le problème est d'utiliser un gestionnaire de transactions incorrectes, par conséquent, l'entité n'a pas été vidées à la base de données. Voir l'explication de Pascal.
dans le premier cas, l'identifiant est un nombre entier
dans le second, l'identifiant est une chaîne
un entier ne sera jamais égale à une chaîne