Hibernate.org Community Documentation

- Anterior
- Próxima

## Capítulo 16. HQL: A Linguagem de Consultas do Hibernate

O Hibernate vem com uma poderosa linguagem de consulta (HQL) que é muito parecida com o SQL. No entanto, comparado com o SQL o HQL é totalmente orientado à objetos, e compreende noções de herança, polimorfismo e associações.

## 16.1. Diferenciação de maiúscula e minúscula

As Consultas não diferenciam maiúscula de minúscula, exceto pelo nomes das classes e propriedades Java. Portanto, `SeLeCT` é o mesmo que `sELEct` que é o mesmo que `SELECT`, mas `org.hibernate.eg.FOO` não é `org.hibernate.eg.Foo` e `foo.barSet` não é `foo.BARSET`.

Esse manual usa as palavras chave HQL em letras minúsculas. Alguns usuários acreditam que com letras maiúsculas as consultas ficam mais legíveis, mas nós acreditamos que este formato não é apropriado para o código Java.

## 16.2. A cláusula from

A consulta mais simples possível do Hibernate é a seguinte:

    from eg.Cat

Isto simplesmente retornará todas as instâncias da classe `eg.Cat`. Geralmente não precisamos qualificar o nome da classe, uma vez que o `auto-import` é o padrão. Por exemplo:

    from Cat

Com o objetivo de referir-se ao `Cat` em outras partes da consulta, você precisará determinar um alias. Por exemplo:

    from Cat as cat

Essa consulta atribui um alias a `cat` para as instâncias de `Cat`, portanto poderemos usar esse alias mais tarde na consulta. A palavra chave `as` é opcional. Você também pode escrever assim:

    from Cat cat

Classes múltiplas podem ser envolvidas, resultando em um produto cartesiano ou união "cruzada".

    from Formula, Parameter

    from Formula as form, Parameter as param

É considerada uma boa prática nomear alias de consulta, utilizando uma letra minúscula inicial, consistente com os padrões de nomeação Java para variáveis locais (ex.: `domesticCat`).

## 16.3. Associações e uniões

Podemos também atribuir aliases em uma entidade associada, ou mesmo em elementos de uma coleção de valores, usando uma `join`. Por exemplo:

    from Cat as cat
        inner join cat.mate as mate
        left outer join cat.kittens as kitten

    from Cat as cat left join cat.mate.kittens as kittens

    from Formula form full join form.parameter param

Os tipos de uniões suportados foram inspirados no ANSI SQL:

- `inner join`

- `left outer join`

- `right outer join`

- `união completa` (geralmente não é útil)

As construções `inteiro`, `união esquerda externa` e `união direita externa` podem ser abreviadas.

    from Cat as cat
        join cat.mate as mate
        left join cat.kittens as kitten

Você pode fornecer condições extras de união usando a palavra chave do HQL `with`.

    from Cat as cat
        left join cat.kittens as kitten
            with kitten.bodyWeight
    > 10.0

A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select. This is particularly useful in the case of a collection. It effectively overrides the outer join and lazy declarations of the mapping file for associations and collections. See Seção 21.1, “Estratégias de Busca ” for more information.

    from Cat as cat
        inner join fetch cat.mate
        left join fetch cat.kittens

Geralmente, uma união de busca não precisa atribuir um alias, pois o objeto associado não deve ser usado na cláusula `where` (ou em qualquer outra cláusula). Também, os objetos associados não são retornados diretamente nos resultados da consulta. Ao invés disso, eles devem ser acessados usando o objeto pai. A única razão pela qual precisariamos de um alias é quando fazemos uma união de busca recursivamente em uma coleção adicional:

    from Cat as cat
        inner join fetch cat.mate
        left join fetch cat.kittens child
        left join fetch child.kittens

Observe que a construção `busca` não deve ser usada em consultas invocadas usando `iterate()` (embora possa ser usado com `scroll()`). O `Fetch` também não deve ser usado junto com o `setMaxResults()` ou `setFirstResult()` pois essas operações são baseadas nas linhas retornadas, que normalmente contém duplicidade devido à busca das coleções, então o número de linhas pode não ser o que você espera. A `Fetch` não deve ser usada junto com uma condição `with`. É possível que seja criado um produto cartesiano pela busca de união em mais do que uma coleção em uma consulta, então tome cuidado nesses casos. Uma busca de união em várias coleções pode trazer resultados inesperados para mapeamentos do tipo bag, tome cuidado na hora de formular consultas como essas. Finalmente, observe o seguinte, a `busca de união completa` e `busca de união direita` não são importantes.

Se estiver usando o nível de propriedade busca lazy (com instrumentação de bytecode), é possível forçar o Hibernate a buscar as propriedades lazy imediatamente na primeira consulta, usando `buscar todas as propriedades` .

    from Document fetch all properties order by name

    from Document doc fetch all properties where lower(doc.name) like '%cats%'

## 16.4. Formas de sintáxe de uniões

O HQL suporta duas formas de associação para união: `implícita` e `explícita`.

As consultas apresentadas na seção anterior usam a forma `explícita`, onde a palavra chave união é explicitamente usada na cláusula from. Essa é a forma recomendada.

A forma `implícita` não usa a palavra chave "união". Entretanto, as associações são "diferenciadas" usando pontuação ("." - dot-notation). Uniões`implícitas` podem aparecer em qualquer uma das cláusulas HQL. A união `implícita` resulta em declarações SQL que contém uniões inteiras.

    from Cat as cat where cat.mate.name like '%s%'

## 16.5. Referência à propriedade do identificador

Geralmente, existem duas formas para se referir à propriedade do indentificador de uma entidade:

- A propriedade especial (em letra minúscula) `id` pode ser usada para se referir à propriedade do identificador de uma entidade considerando que a entidade não define uma propriedade não identificadora chamada id.

- Se a entidade definir a propriedade do identificador nomeada, você poderá usar este nome de propriedade.

As referências à composição das propriedades do identificador seguem as mesmas regras de nomeação. Se a entidade tiver uma propriedade de não identificador chamada id, a composição da propriedade do identificador pode somente ser referenciada pelo seu nome definido. Do contrário, uma propriedade especial `id` poderá ser usada para referenciar a propriedade do identificador.

## Importante

Observe: esta ação mudou completamente na versão 3.2.2. Nas versões anteriores o `id` sempre referia-se à propriedade do identificador não importando seu nome atual. Uma ramificação desta decisão era que as propriedades do não identificador de chamadas `id` nunca poderiam ser referenciadas nas consultas do Hibernate.

## 16.6. A cláusula select

A cláusula `select` seleciona quais objetos e propriedades retornam no resultado da consulta. Considere:

    select mate
    from Cat as cat
        inner join cat.mate as mate

A consulta selecionará `mate`s (parceiros), de outros `Cat`s. Atualmente, podemos expressar a consulta de forma mais compacta como:

    select cat.mate from Cat cat

As consultas podem retornar propriedades de qualquer tipo de valor, incluindo propriedades de tipo de componente:

    select cat.name from DomesticCat cat
    where cat.name like 'fri%'

    select cust.name.firstName from Customer as cust

As consultas podem retornar múltiplos objetos e/ou propriedades como uma matriz do tipo `Object[]`:

    select mother, offspr, mate.name
    from DomesticCat as mother
        inner join mother.mate as mate
        left outer join mother.kittens as offspr

Ou como um `List`:

    select new list(mother, offspr, mate.name)
    from DomesticCat as mother
        inner join mother.mate as mate
        left outer join mother.kittens as offspr

Ou - considerando que a classe `Family` tenha um construtor apropriado - como um objeto Java typesafe atual:

    select new Family(mother, mate, offspr)
    from DomesticCat as mother
        join mother.mate as mate
        left join mother.kittens as offspr

Pode-se designar alias à expressões selecionadas usando `as`:

    select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
    from Cat cat

Isto é bem mais útil quando usado junto `com` `selecione novo mapa`:

    select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
    from Cat cat

Esta consulta retorna um `Mapa` de referências para valores selecionados.

## 16.7. Funções de agregação

As consultas HQL podem retornar o resultado de funções agregadas nas propriedades:

    select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
    from Cat cat

As funções agregadas suportadas são:

- `avg(...), sum(...), min(...), max(...)`

- `count(*)`

- `count(...), count(distinct ...), count(all...)`

Pode-se usar operadores aritméticos, concatenação e funções SQL reconhecidas na cláusula select:

    select cat.weight + sum(kitten.weight)
    from Cat cat
        join cat.kittens kitten
    group by cat.id, cat.weight

    select firstName||' '||initial||' '||upper(lastName) from Person

As palavras `distinct` e `all` podem ser usadas e têm a mesma semântica que no SQL.

    select distinct cat.name from Cat cat

    select count(distinct cat.name), count(cat) from Cat cat

## 16.8. Pesquisas Polimórficas

A consulta:

    from Cat as cat

retorna instâncias não só de `Cat`, mas também de subclasses como `DomesticCat`. As consultas do Hibernate podem nomear qualquer classe Java ou interface na cláusula `from`. A consulta retornará instâncias de todas as classes persistentes que extendam a determinada classe ou implemente a determinada interface. A consulta a seguir, poderia retornar todos os objetos persistentes:

    from java.lang.Object o

A interface `Named` pode ser implementada por várias classes persistentes:

    from Named n, Named m where n.name = m.name

Note que as duas últimas consultas requerem mais de um SQL `SELECT`. Isto significa que a cláusula `order by` não ordena corretamente todo o resultado. Isso também significa que você não pode chamar essas consultas usando `consulta.scroll()`.

## 16.9. A cláusula where

A cláusula `where` permite estreitar a lista de instâncias retornadas. Se não houver referência alguma, pode-se referir à propriedades pelo nome:

    from Cat where name='Fritz'

Se houver uma referência, use o nome da propriedade qualificada:

    from Cat as cat where cat.name='Fritz'

Isto retorna instâncias de `Cat` com nome ‘Fritz’.

A seguinte consulta:

    select foo
    from Foo foo, Bar bar
    where foo.startDate = bar.date

retornará todas as instâncias de `Foo`, para cada um que tiver uma instância de `bar` com a propriedade `date` igual a propriedade `startDate` de `Foo`. Expressões de caminho compostas fazem da cláusula `where`, extremamente poderosa. Consideremos:

    from Cat cat where cat.mate.name is not null

Esta consulta traduz para uma consulta SQL com uma tabela (inner) união. Por exemplo:

    from Foo foo
    where foo.bar.baz.customer.address.city is not null

resultaria numa consulta que necessitasse de união de quatro tabelas, no SQL.

O operador `=` pode ser usado para comparar não apenas propriedades, mas também instâncias:

    from Cat cat, Cat rival where cat.mate = rival.mate

    select cat, mate
    from Cat cat, Cat mate
    where cat.mate = mate

The special property (lowercase) `id` can be used to reference the unique identifier of an object. See Seção 16.5, “Referência à propriedade do identificador ” for more information.

    from Cat as cat where cat.id = 123

    from Cat as cat where cat.mate.id = 69

A segunda consulta é eficiente e não requer nenhuma união de tabelas.

As propriedades de identificadores compostas também podem ser usadas. Considere o seguinte exemplo onde `Person` possui identificadores compostos que consistem de `country` e `medicareNumber`:

    from bank.Person person
    where person.id.country = 'AU'
        and person.id.medicareNumber = 123456

    from bank.Account account
    where account.owner.id.country = 'AU'
        and account.owner.id.medicareNumber = 123456

Mais uma vez, a segunda consulta não precisa de nenhuma união de tabela.

See Seção 16.5, “Referência à propriedade do identificador ” for more information regarding referencing identifier properties)

Da mesma forma, a propriedade especial `class` acessa o valor discriminador da instância, no caso de persistência polimórfica. O nome de uma classe Java inclusa em uma cláusula where, será traduzida para seu valor discriminante.

    from Cat cat where cat.class = DomesticCat

You can also use components or composite user types, or properties of said component types. See Seção 16.17, “Componentes” for more information.

Um tipo "any" possui as propriedades `id` e `class` especiais, nos permitindo expressar uma união da seguinte forma (onde `AuditLog.item` é uma propriedade mapeada `com``<any>`):

    from AuditLog log, Payment payment
    where log.item.class = 'Payment' and log.item.id = payment.id

Veja que `log.item.class` e `payment.class` podem referir-se à valores de colunas de banco de dados completamente diferentes, na consulta acima.

## 16.10. Expressões

As expressões permitidas na cláusula `where` incluem o seguinte:

- operadores matemáticos: `+, -, *, /`

- operadores de comparação binários: `=, >=, <=, <>, !=, like`

- operadores lógicos `and, or, not`

- Parênteses `( )` que indica o agrupamento

- `in`, `not in`, `between`, `is null`, `is not null`, `is empty`, `is not empty`, `member of` and `not member of`

- case "simples" , `case ... when ... then ... else ... end`, and "searched" case, `case when ... then ... else ... end`

- concatenação de string `...||...` ou `concat(...,...)`

- `current_date()`, `current_time()` e `current_timestamp()`

- `second(...)`, `minute(...)`, `hour(...)`, `day(...)`, `month(...)` e `year(...)`

- qualquer função ou operador definidos pela EJB-QL 3.0: `substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()`

- `coalesce()` and `nullif()`

- `str()` para converter valores numéricos ou temporais para uma string de leitura

- `cast(... as ...)`, onde o segundo argumento é o nome do tipo hibernate, e`extract(... from ...)` se ANSI `cast()` e `extract()` é suportado pelo banco de dados adjacente

- A função HQL `index()` , que se aplicam às referências de coleçôes associadas e indexadas

- As funções HQL que retornam expressões de coleções de valores: `size(), minelement(), maxelement(), minindex(), maxindex()`, junto com o elemento especial, `elements()` e funções de `índices` que podem ser quantificadas usando `some, all, exists, any, in`.

- Qualquer função escalar suportada pelo banco de dados como `sign()`, `trunc()`, `rtrim()` e `sin()`

- Parâmetros posicionais ao estilo JDBC `?`

- Parâmetros nomeados `:name`, `:start_date` e `:x1`

- Literais SQL `'foo'`, `69`, `6.66E+2`, `'1970-01-01 10:00:01.0'`

- Constantes Java `final estático público` `ex: Color.TABBY`

`in` e `between` podem ser usadas da seguinte maneira:

    from DomesticCat cat where cat.name between 'A' and 'B'

    from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )

As formas negativas podem ser escritas conforme segue abaixo:

    from DomesticCat cat where cat.name not between 'A' and 'B'

    from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )

Da mesma forma, `is null` e `is not null` podem ser usados para testar valores nulos.

Booleanos podem ser facilmente usados em expressões, declarando as substituições da consulta HQL, na configuração do Hibernate:

    <property name="hibernate.query.substitutions"
    >true 1, false 0</property
    >

Isso irá substituir as palavras chave `true` e `false` `pelos` literais `1` e `0` na tradução do HQL para SQL.

    from Cat cat where cat.alive = true

Pode-se testar o tamanho de uma coleção com a propriedade especial `size` ou a função especial `size()`.

    from Cat cat where cat.kittens.size
    > 0

    from Cat cat where size(cat.kittens)
    > 0

Para coleções indexadas, você pode se referir aos índices máximo e mínimo, usando as funções `minindex` e `maxindex`. Igualmente, pode-se referir aos elementos máximo e mínimo de uma coleção de tipos básicos usando as funções `minelement` e `maxelement`. Por exemplo:

    from Calendar cal where maxelement(cal.holidays)
    > current_date

    from Order order where maxindex(order.items)
    > 100

    from Order order where minelement(order.items)
    > 10000

As funções SQL `any, some, all, exists, in` são suportadas quando passado o elemento ou o conjunto de índices de uma coleção (`elements` e `índices` de funções) ou o resultado de uma subconsulta (veja abaixo):

    select mother from Cat as mother, Cat as kit
    where kit in elements(foo.kittens)

    select p from NameList list, Person p
    where p.name = some elements(list.names)

    from Cat cat where exists elements(cat.kittens)

    from Player p where 3
    > all elements(p.scores)

    from Show show where 'fizard' in indices(show.acts)

Note que essas construções - `tamanho`, `elementos`, `índices`, `minindex`, `maxindex`, `minelement`, `maxelement` – só podem ser usados na cláusula where do Hibernate3.

Elementos de coleções com índice (matriz, listas, mapas) podem ser referenciadas pelo índice (apenas na cláusula where):

    from Order order where order.items[0].id = 1234

    select person from Person person, Calendar calendar
    where calendar.holidays['national day'] = person.birthDay
        and person.nationality.calendar = calendar

    select item from Item item, Order order
    where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11

    select item from Item item, Order order
    where order.items[ maxindex(order.items) ] = item and order.id = 11

A expressão entre colchetes `[]` pode ser até uma expressão aritimética:

    select item from Item item, Order order
    where order.items[ size(order.items) - 1 ] = item

O HQL também provê a função interna `index()` para elementos de associação um-para-muitos ou coleção de valores.

    select item, index(item) from Order order
        join order.items item
    where index(item) < 5

Funções escalares SQL, suportadas pelo banco de dados subjacente podem ser usadas:

    from DomesticCat cat where upper(cat.name) like 'FRI%'

Se ainda não estiver totalmente convencido, pense o quão maior e menos legível poderia ser a consulta a seguir, em SQL:

    select cust
    from Product prod,
        Store store
        inner join store.customers cust
    where prod.name = 'widget'
        and store.location.name in ( 'Melbourne', 'Sydney' )
        and prod = all elements(cust.currentOrder.lineItems)

Hint: algo como:

    SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
    FROM customers cust,
        stores store,
        locations loc,
        store_customers sc,
        product prod
    WHERE prod.name = 'widget'
        AND store.loc_id = loc.id
        AND loc.name IN ( 'Melbourne', 'Sydney' )
        AND sc.store_id = store.id
        AND sc.cust_id = cust.id
        AND prod.id = ALL(
            SELECT item.prod_id
            FROM line_items item, orders o
            WHERE item.order_id = o.id
                AND cust.current_order = o.id
        )

## 16.11. A cláusula ordenar por

A lista retornada pela consulta pode ser ordenada por qualquer propriedade da classe ou componentes retornados:

    from DomesticCat cat
    order by cat.name asc, cat.weight desc, cat.birthdate

As opções `asc` ou `desc` indicam ordem crescente ou decrescente, respectivamente.

## 16.12. A cláusula agrupar por

Uma consulta que retorne valores agregados, podem ser agrupados por qualquer propriedade de uma classe ou componentes retornados:

    select cat.color, sum(cat.weight), count(cat)
    from Cat cat
    group by cat.color

    select foo.id, avg(name), max(name)
    from Foo foo join foo.names name
    group by foo.id

Uma cláusula `having` também é permitida.

    select cat.color, sum(cat.weight), count(cat)
    from Cat cat
    group by cat.color
    having cat.color in (eg.Color.TABBY, eg.Color.BLACK)

Funções SQL e funções agregadas são permitidas nas cláusulas `having` e `order by`, se suportadas pelo banco de dados subjacentes (ex: não no MeuSQL).

    select cat
    from Cat cat
        join cat.kittens kitten
    group by cat.id, cat.name, cat.other, cat.properties
    having avg(kitten.weight)
    > 100
    order by count(kitten) asc, sum(kitten.weight) desc

Note que, nem a cláusula `group by` ou `order by` podem conter expressões aritméticas. O Hibernate também não expande atualmente uma entidade agrupada, portanto você não pode escrever `group by cat` caso todas as propriedades do `cat` não estiverem agregadas. Você precisa listar claramente todas as propriedades não-agregadas.

## 16.13. Subconsultas

Para bancos de dados que suportam subseleções, o Hibernate suporta subconsultas dentro de consultas. Uma subconsulta precisa estar entre parênteses (normalmente uma chamada de função agregada SQL). Mesmo subconsultas co-relacionadas (subconsultas que fazem referência à alias de outras consultas), são aceitas.

    from Cat as fatcat
    where fatcat.weight
    > (
        select avg(cat.weight) from DomesticCat cat
    )

    from DomesticCat as cat
    where cat.name = some (
        select name.nickName from Name as name
    )

    from Cat as cat
    where not exists (
        from Cat as mate where mate.mate = cat
    )

    from DomesticCat as cat
    where cat.name not in (
        select name.nickName from Name as name
    )

    select cat.id, (select max(kit.weight) from cat.kitten kit)
    from Cat as cat

Note que HQL subconsultas podem aparecer apenas dentro de cláusulas select ou where.

Note that subqueries can also utilize `row value constructor` syntax. See Seção 16.18, “Sintáxe do construtor de valores de linha” for more information.

## 16.14. Exemplos de HQL

As consultas do Hibernate, podem ser muito poderosas e complexas. De fato, o poder da linguagem de consulta é um dos pontos principais na distribuição do Hibernate. Aqui temos algumas consultas de exemplo, muito similares a consultas usadas em um projeto recente. Note que a maioria das consultas que você irá escrever, são mais simples que estas.

A consulta a seguir retorna o id de ordenar, número de ítens e o valor total do ordenar para todos os ordenar não pagos para um cliente particular e valor total mínimo dado, ordenando os resultados por valor total. Para determinar os preços, utiliza-se o catálogo atual. A consulta SQL resultante, usando tabelas `ORDER`, `ORDER_LINE`, `PRODUCT`, `CATALOG` e `PRICE`, têm quatro uniões inteiras e uma subseleção (não correlacionada).

    select order.id, sum(price.amount), count(item)
    from Order as order
        join order.lineItems as item
        join item.product as product,
        Catalog as catalog
        join catalog.prices as price
    where order.paid = false
        and order.customer = :customer
        and price.product = product
        and catalog.effectiveDate < sysdate
        and catalog.effectiveDate
    >= all (
            select cat.effectiveDate
            from Catalog as cat
            where cat.effectiveDate < sysdate
        )
    group by order
    having sum(price.amount)
    > :minAmount
    order by sum(price.amount) desc

Que monstro! Na verdade, na vida real, eu não sou muito afeiçoado à subconsultas, então minha consulta seria mais parecida com isto:

    select order.id, sum(price.amount), count(item)
    from Order as order
        join order.lineItems as item
        join item.product as product,
        Catalog as catalog
        join catalog.prices as price
    where order.paid = false
        and order.customer = :customer
        and price.product = product
        and catalog = :currentCatalog
    group by order
    having sum(price.amount)
    > :minAmount
    order by sum(price.amount) desc

A próxima consulta conta o número de pagamentos em cada status, excluindo todos os pagamentos no status `AWAITING_APPROVAL`, onde a mais recente mudança de status foi feita pelo usuário atual. Traduz-se para uma consulta SQL `com` duas uniões inteiras e uma subseleção correlacionada, nas tabelas `PAYMENT`, `PAYMENT_STATUS` e `PAYMENT_STATUS_CHANGE` .

    select count(payment), status.name
    from Payment as payment
        join payment.currentStatus as status
        join payment.statusChanges as statusChange
    where payment.status.name <
    > PaymentStatus.AWAITING_APPROVAL
        or (
            statusChange.timeStamp = (
                select max(change.timeStamp)
                from PaymentStatusChange change
                where change.payment = payment
            )
            and statusChange.user <
    > :currentUser
        )
    group by status.name, status.sortOrder
    order by status.sortOrder

Se eu tivesse mapeado a coleção `statusChanges` como um List, ao invés de um Set, a consulta teria sido muito mais simples de escrever.

    select count(payment), status.name
    from Payment as payment
        join payment.currentStatus as status
    where payment.status.name <
    > PaymentStatus.AWAITING_APPROVAL
        or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <
    > :currentUser
    group by status.name, status.sortOrder
    order by status.sortOrder

A próxima consulta usa a função `isNull()` do Servidor MS SQL, para retornar todas as contas e pagamentos não efetuados para a organização, para aquele que o usuário atual pertencer. Traduz-se para uma consulta SQL `com` três uniões inteiras, uma união externa e uma subseleção nas tabelas `ACCOUNT`, `PAYMENT`, `PAYMENT_STATUS`, `ACCOUNT_TYPE`, `ORGANIZATION` e `ORG_USER` .

    select account, payment
    from Account as account
        left outer join account.payments as payment
    where :currentUser in elements(account.holder.users)
        and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
    order by account.type.sortOrder, account.accountNumber, payment.dueDate

Para alguns bancos de dados, precisaremos eliminar a subseleção (correlacionada).

    select account, payment
    from Account as account
        join account.holder.users as user
        left outer join account.payments as payment
    where :currentUser = user
        and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
    order by account.type.sortOrder, account.accountNumber, payment.dueDate

## 16.15. Atualização e correção em lote

HQL now supports `update`, `delete` and `insert ... select ...` statements. See Seção 15.4, “Operações no estilo DML” for more information.

## 16.16. Dicas & Truques

Pode-se contar o número de resultados da consulta, sem realmente retorná-los:

    ( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue()

Para ordenar um resultado pelo tamanho de uma coleção, use a consulta a seguir.

    select usr.id, usr.name
    from User as usr
        left join usr.messages as msg
    group by usr.id, usr.name
    order by count(msg)

Se seu banco de dados suporta subseleções, pode-se colocar uma condição sobre tamanho de seleção na cláusula where da sua consulta:

    from User usr where size(usr.messages)
    >= 1

Se seu banco de dados não suporta subseleções, use a consulta a seguir:

    select usr.id, usr.name
    from User usr
        join usr.messages msg
    group by usr.id, usr.name
    having count(msg)
    >= 1

Com essa solução não se pode retornar um `User` sem nenhuma menssagem, por causa da união inteira, a forma a seguir também é útil:

    select usr.id, usr.name
    from User as usr
        left join usr.messages as msg
    group by usr.id, usr.name
    having count(msg) = 0

As propriedades de um JavaBean podem ser limitadas à parâmetros nomeados da consulta:

    Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");

    q.setProperties(fooBean); // fooBean has getName() and getSize()

    List foos = q.list();

As coleções são pagináveis, usando a interface `Query` com um filtro:

    Query q = s.createFilter( collection, "" ); // the trivial filter

    q.setMaxResults(PAGE_SIZE);

    q.setFirstResult(PAGE_SIZE * pageNumber);

    List page = q.list();

Os elementos da coleção podem ser ordenados ou agrupados usando um filtro de consulta:

    Collection orderedCollection = s.filter( collection, "order by this.amount" );

    Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );

Pode-se achar o tamanho de uma coleção sem inicializá-la:

    ( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue();

## 16.17. Componentes

Os componentes podem ser usados de quase todas as formas que os tipos de valores simples são usados nas consultas HQL. Eles podem aparecer na cláusula `select`:

    select p.name from Person p

    select p.name.first from Person p

onde a propriedade do nome da Person é um componente. Os componentes também podem ser utilizados na cláusula `where`:

    from Person p where p.name = :name

    from Person p where p.name.first = :firstName

Os componentes também podem ser usados na cláusula `order by`:

    from Person p order by p.name

    from Person p order by p.name.first

Outro uso comum dos componentes é nos row value constructors.

## 16.18. Sintáxe do construtor de valores de linha

O HQL suporta o uso da sintáxe ANSI SQL `row value constructor`, algumas vezes chamado de sintáxe `tupla`, embora o banco de dados adjacente possa não suportar esta noção. Aqui nós geralmente nos referimos às comparações de valores múltiplos, tipicamente associada aos componentes. Considere uma entidade Person que define um componente de nome:

    from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt'

Esta é uma sintáxe válida, embora um pouco verbosa. Seria ótimo tornar essa sintáxe um pouco mais concisa e utilizar a sintáxe `row value constructor`:

    from Person p where p.name=('John', 'Jingleheimer-Schmidt')

Pode também ser útil especificar isto na cláusula `select`:

    select p.name from Person p

Com o uso da sintáxe `row value constructor`, e que pode ser de benéfico, seria quando utilizar as subconsultas que precisem comparar com os valores múltiplos:

    from Cat as cat
    where not ( cat.name, cat.color ) in (
        select cat.name, cat.color from DomesticCat cat
    )

Ao decidir se você quer usar esta sintáxe ou não, deve-se considerar o fato de que a consulta será dependente da ordenação das sub-propriedades do componente no metadados.

Copyright © 2004 Red Hat, Inc.

- AnteriorCapítulo 15. Batch processing
- Acima
- Principal
- PróximaCapítulo 17. Consultas por critérios