Por que um objeto é encontrado pelo ID no JPA, mas não através de uma consulta JPQL?
Pergunta
Eu tenho um caso de teste Junit 4 com a primavera @Transactional
Anotação que salva um objeto e, em seguida, tenta encontrá -lo. O caso de teste passa quando eu uso esta implementação:
@Override
public EventSummary findEventSummaryById(Integer id) {
return em.find(EventSummary.class, id);
}
Ele falha quando eu uso essa implementação (e depois altere qual método eu chamo no caso de teste):
@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;
}
Solução
Se você estiver usando o modo de descarga padrão (AUTO
) e se você estiver executando sua consulta em uma transação, a especificação JPA garante que uma consulta não retorne dados obsoletos ou incorretos:
3.6.2 Consultas e FlushMode
A configuração do modo de descarga afeta o resultado de uma consulta da seguinte maneira.
Quando as consultas são executadas dentro de uma transação, se
FlushModeType.AUTO
está definido noQuery
objeto, ou se a configuração do modo de descarga para o contexto de persistência forAUTO
(o padrão) e uma configuração de modo de descarga não foi especificada para oQuery
Objeto, o provedor de persistência é responsável por garantir que todas as atualizações do estado de todas as entidades no contexto de persistência que possam afetar o resultado da consulta sejam visíveis para o processamento da consulta. A implementação do provedor de persistência pode conseguir isso liberando essas entidades para o banco de dados ou por outros meios. SeFlushModeType.COMMIT
está definido, o efeito das atualizações feitas às entidades no contexto de persistência nas consultas não é especificado.public enum FlushModeType { COMMIT, AUTO }
Se não houver transação ativa, o provedor de persistência não deve liberar para o banco de dados.
Supondo que você esteja usando AUTO
, verifique o lado transacional.
Outras dicas
A entidade está na sessão atual (gerente de entidade) - está em estado persistente, esperando para ser liberado. O método GET primeiro verifica o conteúdo da sessão e, se não for encontrado, gira no banco de dados subjacente. No seu caso, a entidade acabou de ser salva na mesma sessão, por isso é encontrada e devolvida.
ATUALIZAÇÃO: Acontece que o problema está usando um gerenciador de transações incorreto; portanto, a entidade não foi liberada no banco de dados. Veja a explicação de Pascal.
No primeiro caso, o ID é um número inteiro
No segundo, o id é uma string
Um número inteiro nunca será igual a uma corda