Pergunta

Procuro um construtor para HQL em Java.Eu quero me livrar de coisas como:

StringBuilder builder = new StringBuilder()
    .append("select stock from ")
    .append( Stock.class.getName() )
    .append( " as stock where stock.id = ")
    .append( id );

Eu prefiro ter algo como:

HqlBuilder builder = new HqlBuilder()
    .select( "stock" )
    .from( Stock.class.getName() ).as( "stock" )
    .where( "stock.id" ).equals( id );

Pesquisei um pouco no Google e não consegui encontrar nenhum.

Eu escrevi um rápido e idiota HqlBuilder que atenda às minhas necessidades por enquanto, mas adoraria encontrar um que tenha mais usuários e testes do que eu sozinho.

Observação:Gostaria de poder fazer coisas assim e muito mais, o que não consegui fazer com a API de critérios:

select stock
from com.something.Stock as stock, com.something.Bonus as bonus
where stock.someValue = bonus.id

ou seja.selecione todas as ações cuja propriedade someValue aponta para qualquer bônus da tabela de bônus.

Obrigado!

Foi útil?

Solução

@Sébastien Rocca-Serra
Agora estamos chegando a algum lugar concreto.O tipo de junção que você está tentando fazer não é realmente possível por meio da API de critérios, mas uma subconsulta deve realizar a mesma coisa.Primeiro você cria um DetachedCriteria para a tabela de bônus, então use o IN operador para someValue.

DetachedCriteria bonuses = DetachedCriteria.forClass(Bonus.class);
List stocks = session.createCriteria(Stock.class)
    .add(Property.forName("someValue").in(bonuses)).list();

Isto é equivalente a

select stock
from com.something.Stock as stock
where stock.someValue in (select bonus.id from com.something.Bonus as bonus)

A única desvantagem seria se você tivesse referências a tabelas diferentes em someValue e seus IDs não são exclusivos em todas as tabelas.Mas sua consulta sofreria da mesma falha.

Outras dicas

Não é API de critérios fazer isso por você?Parece quase exatamente com o que você está pedindo.

Para uma abordagem segura para o seu problema, considere Querydsl.

A consulta de exemplo se torna

HQLQuery query = new HibernateQuery(session);
List<Stock> s = query.from(stock, bonus)
  .where(stock.someValue.eq(bonus.id))
  .list(stock);

Querydsl usa APT para geração de código como JPA2 e suporta coleções JPA/Hibernate, JDO, SQL e Java.

Eu sou o mantenedor do Querydsl, então esta resposta é tendenciosa.

Para outro dsl de consulta com segurança de tipo, eu recomendo http://www.torpedoquery.org.A biblioteca ainda é jovem, mas oferece segurança de tipo usando diretamente as classes da sua entidade.Isso significa erros iniciais do compilador quando a consulta não se aplica mais antes da refatoração ou redesenho.

Eu também forneci um exemplo.Acho que pelas suas postagens você estava tentando fazer uma restrição de subconsulta, então baseei o exemplo nisso:

import static org.torpedoquery.jpa.Torpedo.*;

Bonus bonus = from(Bonus.class);
Query subQuery = select(bonus.getId());

Stock stock = from(Stock.class);
where(stock.getSomeValue()).in(subQuery);

List<Stock> stocks = select(stock).list(entityManager);

Parece que você deseja usar a API de consulta de critérios incorporada ao Hibernate.Para fazer sua consulta acima ficaria assim:

List<Stock> stocks = session.createCriteria(Stock.class)
    .add(Property.forName("id").eq(id))
    .list();

Se você ainda não tem acesso à sessão do Hibernate, você pode usar 'DetachedCriteria' assim:

DetachedCriteria criteria = DetachedCriteria.forClass(Stock.class) 
    .add(Property.forName("id").eq(id));

Se você deseja obter todas as ações que possuem bônus com um ID específico, você pode fazer o seguinte:

DetachedCriteria criteria = DetachedCriteria.forClass(Stock.class)
     .createCriteria("Stock")
          .add(Property.forName("id").eq(id)));

Para mais informações confira Consultas de critérios dos documentos do Hibernate

@Sébastien Rocca-Serra

select stock
from com.something.Stock as stock, com.something.Bonus as bonus
where stock.bonus.id = bonus.id

Isso é apenas uma junção.O Hibernate faz isso automaticamente, se e somente se você tiver o mapeamento entre Stock e Bonus configurar e se bonus é uma propriedade de Stock. Criteria.list() retornará Stock objetos e você apenas chama stock.getBonus().

Observe, se você quiser fazer algo como

select stock
from com.something.Stock as stock
where stock.bonus.value > 1000000

Você precisa usar Criteria.createAlias().Seria algo como

session.createCriteria(Stock.class).createAlias("bonus", "b")
   .add(Restrictions.gt("b.value", 1000000)).list()

A API de critérios não fornece todas as funcionalidades disponíveis em HQL.Por exemplo, você não pode fazer mais de uma junção na mesma coluna.

Por que você não usa CONSULTAS NOMEADAS?O visual muito mais clean:

Person person = session.getNamedQuery("Person.findByName")
                             .setString(0, "Marcio")
                             .list();

Eu escrevi uma solução GPL para OMERO que você pode facilmente construir e adequada à sua situação.

Uso:

QueryBuilder qb = new QueryBuilder();
qb.select("img");
qb.from("Image", "img");
qb.join("img.pixels", "pix", true, false);

// Can't join anymore after this
qb.where(); // First
qb.append("(");
qb.and("pt.details.creationTime > :time");
qb.param("time", new Date());
qb.append(")");
qb.and("img.id in (:ids)");
qb.paramList("ids", new HashSet());
qb.order("img.id", true);
qb.order("this.details.creationEvent.time", false);

Funciona como uma máquina de estado "select->from->join->where->order", etc.e acompanha parâmetros opcionais.Houve diversas consultas que a API Criteria não pôde realizar (consulte HHH-879), então no final foi mais simples escrever essa pequena classe para encapsular o StringBuilder.(Observação:há um bilhete HHH-2407 descrevendo um ramo do Hibernate que deve unificar os dois.Depois disso, provavelmente faria sentido visitar novamente a API de critérios)

Dê uma olhada no pacote de pesquisa disponível no hibernate-genérico-dao projeto.Esta é uma implementação bastante decente do HQL Builder.

Eu sei que esse tópico é bem antigo, mas eu também estava procurando por um HqlBuilder e encontrei isso projeto "protetor de tela"
Não é um screensaver do Windows, é um "Sistema de gerenciamento de informações de laboratório (LIMS) para instalações de triagem de alto rendimento (HTS) que realizam telas de moléculas pequenas e RNAi."

Ele contém um HQLBuilder que parece muito bom.
Aqui está uma lista de exemplos de métodos disponíveis:

...
HqlBuilder select(String alias);
HqlBuilder select(String alias, String property);
HqlBuilder from(Class<?> entityClass, String alias);
HqlBuilder fromFetch(String joinAlias, String joinRelationship, String alias);
HqlBuilder where(String alias, String property, Operator operator, Object value);
HqlBuilder where(String alias, Operator operator, Object value);
HqlBuilder where(String alias1, Operator operator, String alias2);
HqlBuilder whereIn(String alias, String property, Set<?> values);
HqlBuilder whereIn(String alias, Set<?> values);
HqlBuilder where(Clause clause);
HqlBuilder orderBy(String alias, String property);
HqlBuilder orderBy(String alias, SortDirection sortDirection);
HqlBuilder orderBy(String alias, String property, SortDirection sortDirection);
String toHql();
...

Agora também estão disponíveis o padrão Tipo JPA seguro consulta e um padrão menos padrão, mas também bom Consulta de objeto

Exemplos:

Tipo JPA seguro

EntityManager em = ...
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Stock> c = qb.createQuery(Stock.class);
Root<Stock> = c.from(Stock.class);
Predicate condition = qb.eq(p.get(Stock_.id), id);
c.where(condition);
TypedQuery<Stock> q = em.createQuery(c); 
List<Stock> result = q.getResultList();

Consulta de objeto

EntityManager em = ...
ObjectQuery<Stock> query = new GenericObjectQuery<Stock>(Stock.class);
Stock toSearch = query.target();
query.eq(toSearch.getId(),id);
List<Stock> res = (List<Stock>)JPAObjectQuery.execute(query, em);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top