Hibernate.orgCommunity Documentation
Hibernate utiliza un lenguaje de consulta potente (HQL) que se parece a SQL. Sin embargo, comparado con SQL, HQL es completamente orientado a objetos y comprende nociones como herencia, polimorfismo y asociación.
La consulta posible más simple de Hibernate es de esta manera:
from eg.Cat
from Cat
from Cat as cat
from Cat cat
from Formula, Parameter
from Formula as form, Parameter as param
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
Los tipos de uniones soportadas se tomaron prestados de ANSI SQL
Las construcciones inner join
, left outer join
y right outer join
se pueden abreviar.
from Cat as cat join cat.mate as mate left join cat.kittens as kitten
Puede proveer condiciones extras de unión utilizando la palabra clave with
de HQL.
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 Sección 21.1, “Estrategias de recuperación” for more information.
from Cat as cat inner join fetch cat.mate left join fetch cat.kittens
Usualmente no se necesita asignársele un alias a una unión de recuperación ya que los objetos asociados no se deben utilizar en la cláusula where
(ni en cualquier otra cláusula). Los objetos asociados no se retornan directamente en los resultados de la consulta. En cambio, se pueden acceder por medio del objeto padre. La única razón por la que necesitaríamos un alias es si estamos uniendo recursivamente otra colección:
from Cat as cat inner join fetch cat.mate left join fetch cat.kittens child left join fetch child.kittens
La construcción fetch
no puede utilizarse en consultas llamadas que usen iterate()
(aunque se puede utilizar scroll()
). Fetch
se debe usar junto con setMaxResults()
o setFirstResult()
ya que estas operaciones se basan en las filas de resultados, las cuales usualmente contienen duplicados para la recuperación de colección temprana, por lo tanto, el número de filas no es lo que se esperaría. Fetch
no se debe usar junto con una condición with
improvisadas. Es posible crear un producto cartesiano por medio de una recuperación por union más de una colección en una consulta, así que tenga cuidado en este caso. La recuperación por unión de múltiples roles de colección también da resultados a veces inesperados para mapeos de bag, así que tenga cuidado de cómo formular sus consultas en este caso. Finalmente, observe que full join fetch
y right join fetch
no son significativos.
Si está utilizando una recuperación perezosa a nivel de propiedad (con instrumentación de código byte), es posible forzar a Hibernate a traer las propiedades perezosas inmediatamente utilizando fetch all properties
.
from Document fetch all properties order by name
from Document doc fetch all properties where lower(doc.name) like '%cats%'
HQL soporta dos formas de unión de asociación: implicit
y explicit
.
from Cat as cat where cat.mate.name like '%s%'
Hay dos maneras de referirse a la propiedad identificadora de una entidad:
select mate from Cat as cat inner join cat.mate as mate
select cat.mate from Cat cat
select cat.name from DomesticCat cat where cat.name like 'fri%'
select cust.name.firstName from Customer as cust
Las consultas pueden retornar múltiples objetos y/o propiedades como un array de tipo Object[]
,
select mother, offspr, mate.name from DomesticCat as mother inner join mother.mate as mate left outer join mother.kittens as offspr
select new list(mother, offspr, mate.name) from DomesticCat as mother inner join mother.mate as mate left outer join mother.kittens as offspr
O asumiendo que la clase Family
tiene un constructor apropiado - como un objeto Java de tipo seguro:
select new Family(mother, mate, offspr) from DomesticCat as mother join mother.mate as mate left join mother.kittens as offspr
Puede asignar alias para expresiones seleccionadas utilizando as
:
select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n from Cat cat
Esto es lo más útil cuando se usa junto con select new map
:
select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n ) from Cat cat
Esta consulta devuelve un Map
de alias a valores seleccionados.
Las consultas HQL pueden incluso retornar resultados de funciones de agregación sobre propiedades:
select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat) from Cat cat
Las funciones de agregación soportadas son:
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
Las palabras clave distinct
y all
se pueden utilizar y tienen las misma semántica que en SQL.
select distinct cat.name from Cat cat select count(distinct cat.name), count(cat) from Cat cat
from Cat as cat
from java.lang.Object o
La interfaz Named
se podría implementar por varias clases persistentes:
from Named n, Named m where n.name = m.name
from Cat where name='Fritz'
Si existe un alias, use un nombre de propiedad calificado:
from Cat as cat where cat.name='Fritz'
Esto retorna instancias de Cat
llamadas 'Fritz'.
select foo from Foo foo, Bar bar where foo.startDate = bar.date
from Cat cat where cat.mate.name is not null
Esta consulta se traduce a una consulta SQL con una unión de tabla (interna). Por ejemplo:
from Foo foo where foo.bar.baz.customer.address.city is not null
terminaría con una consulta que requeriría cuatro uniones de tablas en SQL.
El operador =
se puede utilizar para comparar no sólamente propiedades sino también instancias:
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 Sección 16.5, “Referencia a la propiedad identificadora ” for more information.
from Cat as cat where cat.id = 123 from Cat as cat where cat.mate.id = 69
La segunda consulta es eficiente y no se necesita una unión de tablas.
También se pueden utilizar las propiedades de identificadores compuestos. Considere el siguiente ejemplo en donde Person
tiene identificadores compuestos que consisten de country
y 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
Una vez más, la segunda consulta no requiere una unión de tablas.
See Sección 16.5, “Referencia a la propiedad identificadora ” for more information regarding referencing identifier properties)
La propiedad especial class
acccede al valor discriminador de una instancia en el caso de persistencia polimórfica. Un nombre de clase Java incluído en la cláusula where será traducido a su valor discriminador.
from Cat cat where cat.class = DomesticCat
You can also use components or composite user types, or properties of said component types. See Sección 16.17, “Componentes” for more information.
Un tipo "any" tiene las propiedades especiales id
y class
, permiténdole expresar una unión de la siguiente forma (en donde AuditLog.item
es una propiedad mapeada con <any>
).
from AuditLog log, Payment payment where log.item.class = 'Payment' and log.item.id = payment.id
La log.item.class
y payment.class
harían referencia a los valores de columnas de la base de datos completamente diferentes en la consulta anterior.
Las expresiones utilizadas en la cláusula where
incluyen lo siguiente:
in
, not in
, between
, is null
, is not null
, is empty
, is not empty
, member of
y not member of
second(...)
, minute(...)
, hour(...)
, day(...)
, month(...)
, and year(...)
str()
para convertir valores numéricos o temporales a una cadena legible.
la función index()
de HQL, que se aplica a alias de una colección indexada unida.
Cualquier función escalar SQL soportada por la base de datos como sign()
, trunc()
, rtrim()
y sin()
in
y between
pueden utilizarse así:
from DomesticCat cat where cat.name between 'A' and 'B'
from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )
Las formas negadas se pueden escribir así:
from DomesticCat cat where cat.name not between 'A' and 'B'
from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )
De manera similar, is null
y is not null
se pueden utilizar para probar valores nulos.
<property name="hibernate.query.substitutions" >true 1, false 0</property >
from Cat cat where cat.alive = true
from Cat cat where cat.kittens.size > 0
from Cat cat where size(cat.kittens) > 0
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
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)
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
La expresión dentro de []
puede incluso ser una expresión aritmética:
select item from Item item, Order order where order.items[ size(order.items) - 1 ] = item
select item, index(item) from Order order join order.items item where index(item) < 5
Se pueden utilizar las funciones SQL escalares soportadas por la base de datos subyacente:
from DomesticCat cat where upper(cat.name) like 'FRI%'
Considere qué tan larga y menos leíble sería la siguiente consulta en 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)
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 )
from DomesticCat cat order by cat.name asc, cat.weight desc, cat.birthdate
Los asc
o desc
opcionales indican ordenamiento ascendente o descendente respectivamente.
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
Se permite también una cláusula having
.
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)
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
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 las subconsultas HQL pueden ocurrir sólamente en las cláusulas select o where.
Note that subqueries can also utilize row value constructor
syntax. See Sección 16.18, “Sintaxis del constructor de valores por fila” for more information.
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
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
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
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
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 algunas bases de datos, necesitaríamos eliminar la subselección (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
HQL now supports update
, delete
and insert ... select ...
statements. See Sección 15.4, “Operaciones de estilo DML” for more information.
Puede contar el número de resultados de una consulta sin retornarlos:
( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue()
Para ordenar un resultado por el tamaño de una colección, utilice la siguiente consulta:
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)
from User usr where size(usr.messages) >= 1
Si su base de datos no soporta subselecciones, utilice la siguiente consulta:
select usr.id, usr.name from User usr join usr.messages msg group by usr.id, usr.name having count(msg) >= 1
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
Las propiedades de un JavaBean pueden ser ligadas a los parámetros de consulta con nombre:
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();
Las colecciones son paginables usando la interfaz Query
con un filtro:
Query q = s.createFilter( collection, "" ); // the trivial filter
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();
Los elementos de colección se pueden ordenar o agrupar usando un 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" );
Puede hallar el tamaño de una colección sin inicializarla:
( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue();
select p.name from Person p
select p.name.first from Person p
from Person p where p.name = :name
from Person p where p.name.first = :firstName
Los componentes también se pueden utilizar en la cláusula where
:
from Person p order by p.name
from Person p order by p.name.first
Otro uso común de los componentes se encuentra en row value constructors.
from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt'
from Person p where p.name=('John', 'Jingleheimer-Schmidt')
También puede ser útil especificar esto en la cláusula select
:
select p.name from Person p
from Cat as cat where not ( cat.name, cat.color ) in ( select cat.name, cat.color from DomesticCat cat )
Copyright © 2004 Red Hat, Inc.