Eu tenho uma Order
classe que tem uma lista de OrderTransactions
e mapeei com um mapeamento de Hibernate um-para-muitos assim:
@OneToMany(targetEntity = OrderTransaction.class, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
Estes Order
s também têm um campo orderStatus
, que é usado para filtrar com os seguintes critérios:
public List<Order> getOrderForProduct(OrderFilter orderFilter) {
Criteria criteria = getHibernateSession()
.createCriteria(Order.class)
.add(Restrictions.in("orderStatus", orderFilter.getStatusesToShow()));
return criteria.list();
}
Isso funciona e o resultado é o esperado.
Agora, aqui está minha pergunta : Por que, quando eu defino o tipo de busca explicitamente como EAGER
, os Order
s aparecem várias vezes na lista resultante?
@OneToMany(targetEntity = OrderTransaction.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public List<OrderTransaction> getOrderTransactions() {
return orderTransactions;
}
Como eu teria que alterar meu código de critérios para chegar ao mesmo resultado com a nova configuração?
Respostas:
Este é realmente o comportamento esperado se eu entendi sua configuração corretamente.
Você obtém a mesma
Order
instância em qualquer um dos resultados, mas como agora você está fazendo uma junção com oOrderTransaction
, ela deve retornar a mesma quantidade de resultados que uma junção sql regular retornaráEntão, na verdade, deve aparecer várias vezes. isso é muito bem explicado pelo próprio autor (Gavin King) aqui : Ele explica por que e como ainda obter resultados distintos
Também mencionado no FAQ do Hibernate :
fonte
Além do que é mencionado por Eran, outra forma de obter o comportamento desejado, é definir o transformador de resultado:
fonte
experimentar
por exemplo
}
fonte
Não use List e ArrayList, mas Set e HashSet.
fonte
Usando Java 8 e Streams, adiciono ao meu método de utilitário esta declaração de retorno:
Streams removem duplicatas muito rápido. Eu uso anotações em minha classe Entity assim:
Acho que é melhor no meu aplicativo usar sessão no método onde preciso de dados de banco de dados. Sessão de Closse quando eu terminar. Claro, configurei minha classe Entity para usar o tipo de busca leasy. Eu vou refatorar.
fonte
Tenho o mesmo problema para buscar 2 coleções associadas: o usuário possui 2 funções (Conjunto) e 2 refeições (Lista) e as refeições estão duplicadas.
DISTINCT não ajuda (consulta DATA-JPA):
Finalmente encontrei 2 soluções:
Solução final:
fonte
Em vez de usar hacks como:
Set
ao invés deList
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
que não modificam sua consulta sql, podemos usar (citando especificações JPA)
que modifica a consulta sql resultante, tendo, portanto, um
DISTINCT
nele.fonte
Não parece um bom comportamento aplicar uma junção externa e trazer resultados duplicados. A única solução que resta é filtrar nosso resultado usando fluxos. Obrigado java8 dando uma maneira mais fácil de filtrar.
fonte