HQL: El lenguaje de consulta de Hibernate
- 1. Sensibilidad a mayúsculas
- 2. La cláusula from
- 3. Asociaciones y uniones (joins)
- 4. Formas de sintaxis unida
- 5. Referencia a la propiedad identificadora
- 6. La cláusula select
- 7. Funciones de agregación
- 8. Consultas polimórficas
- 9. La cláusula where
- 10. Expresiones
- 11. La cláusula order by
- 12. La cláusula group by
- 13. Subconsultas
- 14. Ejemplos de HQL
- 15. Declaraciones UPDATE y DELETE masivas
- 16. Consejos y Trucos
- 17. Componentes
- 18. Sintaxis del constructor de valores por fila
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.
1. Sensibilidad a mayúsculas
Las consultas no son sensibles a mayúsculas, a excepción de los nombres de las clases y propiedades Java. De modo que SeLeCT
es lo mismo que sELEct
e igual a SELECT
, pero org.hibernate.eg.FOO
no es lo mismo que org.hibernate.eg.Foo
y foo.barSet
no es igual a foo.BARSET
.
Este manual utiliza palabras clave HQL en minúsculas. Algunos usuarios encuentran que las consultas con palabras clave en mayúsculas son más fáciles de leer, pero esta convención no es apropiada para las peticiones incluidas en código Java.
2. La cláusula from
La consulta posible más simple de Hibernate es de esta manera:
from eg.Cat
Esto retorna todas las instancias de la clase
eg.Cat
. Usualmente no es necesario calificar el nombre de la clase ya que auto-import
es el valor predeterminado. Por ejemplo: from Cat
Con el fin de referirse al Cat
en otras partes de la petición, necesitará asignar un alias. Por ejemplo:
from Cat as cat
Esta consulta asigna el alias cat
a las instancias Cat
, de modo que puede utilizar ese alias luego en la consulta. La palabra clave as
es opcional. También podría escribir:
from Cat cat
Pueden aparecer múltiples clases, lo que causa un producto cartesiano o una unión "cruzada" (cross join).
from Formula, Parameter
from Formula as form, Parameter as param
Se considera como una buena práctica el nombrar los alias de consulta utilizando una inicial en minúsculas, consistente con los estándares de nombrado de Java para las variables locales (por ejemplo, domesticCat
).
3. Asociaciones y uniones (joins)
También puede asignar alias a entidades asociadas o a elementos de una colección de valores utilizando una join
. Por ejemplo:
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
inner join
left outer join
right outer join
full join
(no es útil usualmente)
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 20.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 as cat inner mate child left join fetch 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%'
4. Formas de sintaxis unida
HQL soporta dos formas de unión de asociación: implicit
y explicit
.
Las consultas que se mostraron en la sección anterior todas utilizan la forma explicit
, en donde la palabra clave join se utiliza explícitamente en la claúsula from. Esta es la forma recomendada.
La forma implicit
no utiliza la palabra clave join. Las asociaciones se "desreferencian" utilizando la notación punto. Uniones implicit
pueden aparecer en cualquiera de las cláusulas HQL. La unión implicit
causa uniones internas (inner joins) en la declaración SQL que resulta.
from Cat as cat where cat.mate.name like '%s%'
5. Referencia a la propiedad identificadora
Hay dos maneras de referirse a la propiedad identificadora de una entidad:
La propiedad especial (en minúsculas)
id
se puede utilizar para referenciar la propiedad identificadora de una entidad dado que la entidad no defina un id del nombre de la propiedad no-identificadora.Si la entidad define una propiedad identificadora nombrada, puede utilizar ese nombre de propiedad.
Las referencias a propiedades identificadoras compuestas siguen las mismas reglas de nombramiento. Si la entidad no tiene un id del nombre de la propiedad no-identificadora, la propiedad identificadora compuesta sólamente puede ser referenciada por su nombre definido. De otra manera se puede utilizar la propiedad id
especial para referenciar la propiedad identificadora.
Importante
Observe que esto ha cambiado bastante desde la version 3.2.2. En versiones previas, id
siempre se refería a la propiedad identificadora sin importar su nombre real. Una ramificación de esa decisión fue que las propiedades no-identificadoras nombradas id
nunca podrían ser referenciadas en consultas de Hibernate.
6. La cláusula select
La cláusula select
escoge qué objetos y propiedades devolver en el conjunto de resultados de la consulta. Considere lo siguiente:
select mate
from Cat as cat
inner join cat.mate as mate
La consulta seleccionará mate
s de otros Cat
s. Puede expresar esta consulta de una manera más compacta así:
select cat.mate from Cat cat
Las consultas pueden retornar propiedades de cualquier tipo de valor incluyendo propiedades del tipo componente:
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
O como una 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
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.
7. Funciones de agregación
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:
avg(...), sum(...), min(...), max(...)
count(*)
count(...), count(distinct ...), count(all...)
Puede utilizar operadores aritméticos, concatenación y funciones SQL reconocidas en la 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
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
8. Consultas polimórficas
Una consulta como:
from Cat as cat
devuelve instancias no sólamente de Cat
, sino también de subclases como DomesticCat
. Las consultas de Hibernate pueden nombrar cualquier clase o interfaz Java en la cláusula from
. La consulta retornará instancias de todas las clases persistentes que extiendan esa clase o implementen la interfaz. La siguiente consulta retornaría todos los objetos persistentes.
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
Las dos últimas consultas requerirán más de un SELECT
SQL. Esto significa que la cláusula order by
no ordenará correctamente todo el conjunto que resulte. También significa que no puede llamar estas consulta usando Query.scroll()
.
9. La cláusula where
La cláusula where
le permite refinar la lista de instancias retornadas. Si no existe ningún alias, puede referirse a las propiedades por nombre:
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'.
La siguiente petición:
select foo
from Foo foo, Bar bar
where foo.startDate = bar.date
retornará todas las instancias de Foo
con una instancia de bar
con una propiedad date
igual a la propiedad startDate
del Foo
. Las expresiones de ruta compuestas hacen la cláusula where
extremadamente potente. Tome en consideración lo siguiente:
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 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 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 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.
10. Expresiones
Las expresiones utilizadas en la cláusula where
incluyen lo siguiente:
operadores matemáticos:
+, -, *, /
operadores de comparación binarios:
=, >=, <=, <>, !=, like
operadores lógicos
and, or, not
Paréntesis
( )
que indican agrupaciónin
,not in
,between
,is null
,is not null
,is empty
,is not empty
,member of
ynot member of
Caso "simple",
case ... when ... then ... else ... end
, y caso "buscado",case when ... then ... else ... end
concatenación de cadenas
...||...
oconcat(...,...)
current_date()
,current_time()
ycurrent_timestamp()
second(...)
,minute(...)
,hour(...)
,day(...)
,month(...)
, andyear(...)
Cualquier función u operador definido por EJB-QL 3.0:
substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()
coalesce()
ynullif()
str()
para convertir valores numéricos o temporales a una cadena legible.cast(... as ...)
, donde el segundo argumento es el nombre de un tipo de Hibernate , yextract(... from ...)
sicast()
yextract()
es soportado por la base de datos subyacente.la función
index()
de HQL, que se aplica a alias de una colección indexada unida.Las funciones de HQL que tomen expresiones de ruta valuadas en colecciones:
size(), minelement(), maxelement(), minindex(), maxindex()
, junto con las funciones especialeselements()
eindices
, las cuales se pueden cuantificar utilizandosome, all, exists, any, in
.Cualquier función escalar SQL soportada por la base de datos como
sign()
,trunc()
,rtrim()
ysin()
parámetros posicionales JDBC
?
parámetros con nombre
:name
,:start_date
y:x1
literales SQL
'foo'
,69
,6.66E+2
,'1970-01-01 10:00:01.0'
constantes Java
public static final
eg.Color.TABBY
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.
Los valores booleanos se pueden utilizar fácilmente en expresiones declarando substituciones de consulta HQL en la configuración de Hibernate:
<property name="hibernate.query.substitutions"
>true 1, false 0</property
>
Esto remplazará las palabras clave true
y false
con los literales 1
y 0
en el SQL traducido de este HQL:
from Cat cat where cat.alive = true
Puede comprobar el tamaño de una colección con la propiedad especial size
o la función especial size()
.
from Cat cat where cat.kittens.size
> 0
from Cat cat where size(cat.kittens)
> 0
Para las colecciones indexadas, puede referirse a los índices máximo y mínimo utilizando las funciones minindex
y maxindex
. De manera similar, se puede referir a los elementos máximo y mínimo de una colección de tipo básico utilizando las funciones minelement
y maxelement
. Por ejemplo:
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
Las funciones SQL any, some, all, exists, in
están soportadas cuando se les pasa el conjunto de elementos o índices de una colección (las funciones elements
e indices
) o el resultado de una subconsulta (vea a continuación):
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 estas construcciones - size
, elements
, indices
, minindex
, maxindex
, minelement
, maxelement
- solo se pueden utilizar en la cláusula where en Hibernate3.
Los elementos de colecciones indexadas (arrays, listas, mapas) se pueden referir por índice sólamente en una 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
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
HQL también proporciona la función incorporada index()
, para los elementos de una asociación uno-a-muchos o una colección de valores.
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)
Ayuda: 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
)
11. La cláusula order by
La lista retornada por una consulta se puede ordenar por cualquier propiedad de una clase retornada o componentes:
from DomesticCat cat
order by cat.name asc, cat.weight desc, cat.birthdate
Los asc
o desc
opcionales indican ordenamiento ascendente o descendente respectivamente.
12. La cláusula group by
Una consulta que retorna valores agregados se puede agrupar por cualquier propiedad de una clase retornada o componentes:
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)
Las funciones SQL y las funciones de agregación SQL están permitidas en las cláusulas having
y order by
, si están soportadas por la base de datos subyacente (por ejemplo, no lo están en MySQL).
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
La cláusula group by
ni la cláusula order by
pueden contener expresiones aritméticas. Hibernate tampocoo expande una entidad agrupada así que no puede escribir group by cat
si todas las propiedades de cat
son no-agregadas. Tiene que enumerar todas la propiedades no-agregadas explícitamente.
13. Subconsultas
Para bases de datos que soportan subconsultas, Hibernate soporta subconsultas dentro de consultas. Una subconsulta se debe encerrar entre paréntesis (frecuentemente por una llamada a una función de agregación SQL). Incluso se permiten subconsultas correlacionadas (subconsultas que se refieren a un alias en la consulta exterior).
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 18, “Sintaxis del constructor de valores por fila” for more information.
14. Ejemplos de HQL
Las consultas de Hibernate pueden ser bastante potentes y complejas. De hecho, el poder del lenguaje de consulta es uno de las fortalezas principales de Hibernate. He aquí algunos ejemplos de consultas muy similares a las consultas de proyectos recientes. Note que la mayoría de las consultas que escribirá son mucho más simples que los siguientes ejemplos.
La siguiente consulta retorna el order id, número de items y valor total mínimo dado y el valor de la orden para todas las órdenes no pagadas de un cliente en particular. Los resultados se ordenan de acuerdo al valor total. Al determinar los precios, usa el catálogo actual. La consulta SQL resultante, contra las tablas ORDER
, ORDER_LINE
, PRODUCT
, CATALOG
y PRICE
tiene cuatro uniones interiores y una subselección (no 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
¡Qué monstruo! Realmente, en la vida real, no me gustan mucho las subconsultas, de modo que mi consulta fue realmente algo como esto:
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
La próxima consulta cuenta el número de pagos en cada estado, excluyendo todos los pagos en el estado AWAITING_APPROVAL
donde el cambio más reciente al estado lo hizo el usuario actual. Se traduce en una consulta SQL con dos uniones interiores y una subselección correlacionada contra las tablas PAYMENT
, PAYMENT_STATUS
y 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
Si la colección statusChanges
se mapeara como una lista, en vez de un conjunto, la consulta habría sido mucho más simple de escribir.
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
La próxima consulta utiliza la función isNull()
de MS SQL Server para devolver todas las cuentas y pagos aún no cancelados de la organización a la que pertenece el usuario actual. Se traduce como una consulta SQL con tres uniones interiores, una unión exterior y una subselección contra las tablas ACCOUNT
, PAYMENT
, PAYMENT_STATUS
, ACCOUNT_TYPE
, ORGANIZATION
y 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 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
15. Declaraciones UPDATE y DELETE masivas
HQL now supports update
, delete
and insert ... select ...
statements. See Sección 14.4, “Operaciones de estilo DML” for more information.
16. Consejos y Trucos
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)
Si su base de datos soporta subselecciones, puede colocar una condición sobre el tamaño de selección en la cláusula where de su consulta:
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
Como esta solución no puede retornar un User
con cero mensajes debido a la unión interior, la siguiente forma también es ú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
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();
17. Componentes
Los componentes se pueden utilizar de la misma manera en que se pueden utilizar los tipos de valores simples en consultas HQL. Pueden aparecer en la cláusula select
así:
select p.name from Person p
select p.name.first from Person p
en donde el nombre de la Persona es un componente. Los componentes también se pueden utilizar en la cláusula where
:
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.
18. Sintaxis del constructor de valores por fila
HQL soporta la utilización de la sintaxis row value constructor
de SQL ANSI que a veces se denomina sintaxis tuple
, aunque puede que la base de datos subyacentes no soporte esa noción. Aquí estamos refiriéndonos generalmente a las comparaciones multivaluadas que se asocian típicamente con los componentes. Considere una entidad Persona, la cual define un componente de nombre:
from Person p where p.name.first='John' and p.name.last=
'Jingleheimer-Schmidt'
Esa es una sintaxis válida aunque un poco verbosa. Puede hacerlo un poco más conciso utilizando la sintaxis row value constructor
:
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
También puede ser beneficioso el utilizar la sintaxis row value constructor
cuando se utilizan subconsultas que necesitan compararse con valores múltiples:
from Cat as cat
where not ( cat.name, cat.color ) in (
select cat.name, cat.color from DomesticCat cat
)
Algo que se debe tomar en consideración al decidir si quiere usar esta sintaxis es que la consulta dependerá del orden de las sub-propiedades componentes en los metadatos.
No hay comentarios:
Publicar un comentario