Como você cria uma consulta distinta em HQL

100

Existe uma maneira de criar uma consulta distinta em HQL. Usando a palavra-chave "distinto" ou algum outro método. Não tenho certeza se distinto é um keywork válido para HQL, mas estou procurando o equivalente em HQL da palavra-chave SQL "distinto".

Mike Pone
fonte

Respostas:

124

Aqui está um trecho de hql que usamos. (Os nomes foram alterados para proteger as identidades)

String queryString = "select distinct f from Foo f inner join foo.bars as b" +
                " where f.creationDate >= ? and f.creationDate < ? and b.bar = ?";
        return getHibernateTemplate().find(queryString, new Object[] {startDate, endDate, bar});
Pés
fonte
Eu só usei o hibernate com MySQL - não tenho certeza de como lidar com o problema do mssql.
Feet
56

É importante notar que a distinctpalavra - chave em HQL não mapeia diretamente para a distinctpalavra - chave em SQL.

Se você usar a distinctpalavra - chave em HQL, às vezes o Hibernate usará a distinctpalavra-chave SQL, mas em algumas situações ele usará um transformador de resultado para produzir resultados distintos. Por exemplo, quando você está usando uma junção externa como esta:

select distinct o from Order o left join fetch o.lineItems

Não é possível filtrar duplicatas no nível SQL neste caso, então o Hibernate usa um ResultTransformerpara filtrar duplicatas após a consulta SQL ter sido realizada.

Daniel Alexiuc
fonte
1
Respondido aqui: stackoverflow.com/questions/5471819/…
Daniel Alexiuc
16

faça algo assim da próxima vez

 Criteria crit = (Criteria) session.
                  createCriteria(SomeClass.class).
                  setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

 List claz = crit.list();
Michael
fonte
Isso é subótimo: em vez de descartar as repetições no nível do banco de dados, ele apenas puxará os dados do banco de dados para a memória com as repetições e tudo, e depois descartará as repetições; dependendo da frequência com que os dados se repetem, isso pode aumentar bastante as operações de E / S.
Haroldo_OK
9

Você também pode usar Criteria.DISTINCT_ROOT_ENTITY a consulta Hibernate HQL.

Exemplo:

Query query = getSession().createQuery("from java_pojo_name");
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return query.list();
aadi53
fonte
1
Isso é subótimo: em vez de descartar as repetições no nível do banco de dados, ele apenas puxará os dados do banco de dados para a memória com as repetições e tudo, e depois descartará as repetições; dependendo da frequência com que os dados se repetem, isso pode aumentar bastante as operações de E / S.
Haroldo_OK
4

Tive alguns problemas com transformadores de resultado combinados com consultas HQL. Quando eu tentei

final ResultTransformer trans = new DistinctRootEntityResultTransformer();
qry.setResultTransformer(trans);

não funcionou. Tive que transformar manualmente assim:

final List found = trans.transformList(qry.list());

Com os transformadores Criteria API funcionou muito bem.

Tadeusz Kopec
fonte
para chegar a 10k (:
timmz
3

Minha consulta principal era assim no modelo:

@NamedQuery(name = "getAllCentralFinancialAgencyAccountCd", 
    query = "select distinct i from CentralFinancialAgencyAccountCd i")

E eu ainda não estava obtendo o que considerava resultados "distintos". Eles eram apenas distintos com base em uma combinação de teclas primárias na tabela.

Então, no DaoImplacrescentei uma mudança de linha e acabei obtendo o retorno "distinto" que queria. Um exemplo seria, em vez de ver 00 quatro vezes, agora vejo apenas uma vez. Aqui está o código que adicionei ao DaoImpl:

@SuppressWarnings("unchecked")
public List<CacheModelBase> getAllCodes() {

    Session session = (Session) entityManager.getDelegate();
    org.hibernate.Query q = session.getNamedQuery("getAllCentralFinancialAgencyAccountCd");
    q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // This is the one line I had to add to make it do a more distinct query.
    List<CacheModelBase> codes;
    codes = q.list();
    return codes;       
}

Espero que tenha ajudado! Mais uma vez, isso pode funcionar apenas se você estiver seguindo as práticas de codificação que implementam o serviço, dao e tipo de projeto de modelo.

Nathan Mitchell
fonte
2

Suponha que você tenha uma Entidade do Cliente mapeada para a tabela CUSTOMER_INFORMATION e deseja obter uma lista de nomes distintos do cliente. Você pode usar o snippet abaixo para obter o mesmo.

Query distinctFirstName = session.createQuery("select ci.firstName from Customer ci group by ci.firstName");
Object [] firstNamesRows = distinctFirstName.list();

Espero que ajude. Então, aqui estamos usando group by em vez de palavras-chave distintas.

Também anteriormente achei difícil usar palavras-chave distintas quando desejo aplicá-las a várias colunas. Por exemplo, eu quero obter uma lista de firstName, lastName distintos e agrupar por simplesmente funcionaria. Tive dificuldade em usar distinto neste caso.

chammu
fonte
1

Eu tenho uma resposta para Hibernate Query Language para usar campos distintos. Você pode usar * SELECT DISTINCT (TO_CITY) FROM FLIGHT_ROUTE *. Se você usar a consulta SQL , ele retornará a Lista de String. Você não pode usar o valor de retorno por classe de entidade. Portanto, a resposta para resolver esse tipo de problema é usar HQL com SQL .

FROM FLIGHT_ROUTE F WHERE F.ROUTE_ID IN (SELECT SF.ROUTE_ID FROM FLIGHT_ROUTE SF GROUP BY SF.TO_CITY);

Da instrução de consulta SQL , obteve DISTINCT ROUTE_ID e entrou como uma lista. E a consulta IN filtra o TO_CITY distinto de IN (Lista).

O tipo de retorno é o tipo Entity Bean. Então você pode fazer isso em AJAX, como AutoComplement .

Que tudo fique bem

San Lin Naing
fonte
1

Você pode definir a palavra-chave distinta em seu construtor de critérios como este.

CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Orders> query = builder.createQuery(Orders.class);
Root<Orders> root = query.from(Orders.class);
query.distinct(true).multiselect(root.get("cust_email").as(String.class));

E crie o construtor de campo em sua classe de modelo.

Santosh Singh
fonte
0

Se você precisar usar uma nova palavra-chave para um DTO personalizado em sua instrução select e precisar de elementos distintos , use new out of new como a seguir-

select distinct new com.org.AssetDTO(a.id, a.address, a.status) from Asset as a where ...
Manish Sharma
fonte
0

Você pode simplesmente adicionar GROUP BY em vez de Distinct

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
Rustem
fonte