Дерево страниц

Сравнение версий

Ключ

  • Эта строка добавлена.
  • Эта строка удалена.
  • Изменено форматирование.

Чувствительность к регистру

За исключением имен классов и свойств Java, запросы не учитывают регистр. Таким образом, SeLeCT совпадает с SELEct таким же, как SELECT, но org.hibernate.eg.FOO не является org.hibernate.eg.Foo, а foo.barSet не является foo.BARSET.

В этом руководстве ключевые слова HQL используются в нижнем регистре. Некоторые пользователи находят запросы с ключевыми словами в верхнем регистре более читаемыми, но это соглашение непригодно для запросов, встроенных в код Java.

Секция «from»

Самый простой возможный запрос Hibernate имеет вид:

Блок кода
languagesql
from eg.Cat

Этот запрос возвращает все экземпляры класса eg.Cat. Обычно вам не требуется квалифицировать имя класса, поскольку по умолчанию установлен auto-import. Например:

Блок кода
languagesql
from Cat

Чтобы обратиться к Cat в других частях запроса, вам нужно будет присвоить псевдоним (alias). Например:

Блок кода
languagesql
from Cat as cat
Свойства страницы
Статус

Статус
colourGreen
titleГОТОВО

РазделHQL
панель

Оглавление

Этот запрос присваивает псевдоним cat экземплярам Cat, поэтому вы можете использовать этот псевдоним позже в запросе. Ключевое слово as необязательно. Вы также можете написать:

Блок кода
languagesql
from Cat cat

Может встретиться несколько классов, что приведет к декартовому продукту или «перекрёстному (cross)» соединению (join).

Блок кода
languagesql
from Formula, Parameter

from Formula as form, Parameter as param

Хорошей практикой является записывать псевдонимы, начиная с нижнего регистра, поскольку это согласуется с стандартами именования Java для локальных переменных (например, internalCat).

Ассоциации и объединения (join)

Вы также можете назначать псевдонимы связанным сущностям или элементам коллекции значений с помощью join. Например:

Блок кода
languagesql
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

Поддерживаемые типы соединений заимствованы из ANSI SQL:

  • inner join
  • left outer join
  • right outer join
  • full join (редко полезен)

inner join, left outer join и right outer join могут быть сокращены.

Блок кода
languagesql
from Cat as cat
    join cat.mate as mate
    left join cat.kittens as kitten

Вы можете предоставить дополнительные условия соединения с использованием ключевого слова HQL with.

Блок кода
languagesql
from Cat as cat
    left join cat.kittens as kitten
        with kitten.bodyWeight > 10.0

Соединение «fetch» позволяет инициализировать ассоциации или коллекции значений вместе с их родительскими объектами с использованием одного запроса. Это особенно полезно в случае коллекции. Он эффективно отменяет внешнее объединение и ленивые объявления файла отображения для ассоциаций и коллекций.

Блок кода
languagesql
from Cat as cat
    inner join fetch cat.mate
    left join fetch cat.kittens

fetch join обычно не требует назначать псевдоним, потому что связанные объекты не должны и спользоваться в секции where (или в любой другой секции). Связанные объекты также не возвращаются непосредственно в результатах запроса. Вместо этого к ним можно получить доступ через родительский объект. Единственная причина, по которой вам может понадобиться псевдоним, заключается в том, что вы рекурсивно объединяете выборку (join fetching) дальнейшей коллекции:

Блок кода
languagesql
from Cat as cat
    inner join fetch cat.mate
    left join fetch cat.kittens child
    left join fetch child.kittens

Конструкция fetch не может использоваться в запросах, вызванных с помощью функции iterate() (хотя можно использовать функцию scroll()). Fetch не следует использовать вместе с setMaxResults() или setFirstResult(), так как эти операции основаны на строках результата, которые обычно содержат дубликаты в результирующей коллекции, следовательно, количество строк не является тем, что вы ожидаете. Fetch также не должно использоваться вместе с условием with. Возможно создание декартовой продукции, объединением выборки из нескольких коллекций в запросе, поэтому будьте осторожны в этом случае. Объединение выборки из нескольких ролей коллекции может привести к неожиданным результатам для отображённых bag, поэтому при формулировании запросов в этом случае рекомендуется ручное разграничение. Наконец, обратите внимание, что full join fetch и right join fetch не имеют смысла.

Если вы используете ленивую выборку уровня свойств (с инструментами байт-кода), можно заставить Hibernate немедленно получать ленивые свойства в первом запросе, используя fetch all properties.

Блок кода
languagesql
from Document fetch all properties order by name

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

Формы синтаксиса join

HQL поддерживает две формы объединения: явные (explicit) и неявные (implicit).

Запросы, показанные в предыдущем разделе, используют явную форму, то есть где ключевое слово join явно используется в секции from. Это рекомендуемая форма.

Неявная форма не использует ключевое слово join. Вместо этого ассоциации «разыменовываются» с использованием точечной нотации. неявные объединения могут появляться в любом из секций HQL. Неявный результат объединения во внутренних объединениях в результирующей SQL-инструкции.

Блок кода
languagesql
from Cat as cat where cat.mate.name like '%s%'

Ссылаясь на свойство идентификатора

Существует два способа ссылки на свойство идентификатора сущности:

  • Специальное свойство (нижний регистр) id может использоваться для ссылки на свойство идентификатора сущности, при условии, что сущность не определяет неидентифицирующее свойство с именем id.
  • Если сущность определяет именованное свойство идентификатора, вы можете использовать это имя свойства.

Ссылки на составные свойства идентификатора следуют тем же правилам именования. Если у объекта есть неидентифицирующее свойство с именем id, свойство составного идентификатора может ссылаться только на его определённое имя. В противном случае специальное свойство id может использоваться для ссылки на свойство идентификатора.

Предупреждение
iconfalse

Обратите внимание, что начиная с версии 3.2.2 это поведение значительно изменилось. В предыдущих версиях id всегда ссылался на свойство идентификатора независимо от его фактического имени. Разветвление этого решения заключалось в том, что неидентифицирующие свойства с именем id никогда не смогут получить ссылку в запросах Hibernate.

Секция «select»

Секция select выбирает, какие объекты и свойства возвращать в наборе результатов запроса. Рассмотрим следующее:

Блок кода
languagesql
select mate
from Cat as cat
    inner join cat.mate as mate

В запросе будут выбраны все mate у Cat. Вы можете выразить этот запрос более компактно так:

Блок кода
languagesql
select cat.mate from Cat cat

Запросы могут возвращать свойства любого типа значений, включая свойства типа компонента:

Блок кода
languagesql
select cat.name from DomesticCat cat
where cat.name like 'fri%'
select cust.name.firstName from Customer as cust

Запросы могут возвращать несколько объектов и/или свойств в виде массива типа Object[]:

Блок кода
languagesql
select mother, offspr, mate.name
from DomesticCat as mother
    inner join mother.mate as mate
    left outer join mother.kittens as offspr

Или в виде списка List:

Блок кода
languagesql
select new list(mother, offspr, mate.name)
from DomesticCat as mother
    inner join mother.mate as mate
    left outer join mother.kittens as offspr

Или — если предположить, что класс Family имеет соответствующий конструктор — как фактический типобезопасный Java-объекта:

Блок кода
languagesql
select new Family(mother, mate, offspr)
from DomesticCat as mother
    join mother.mate as mate
    left join mother.kittens as offspr

Вы можете назначить псевдонимы для выбранных выражений, используя as:

Блок кода
languagesql
select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
from Cat cat

Это наиболее полезно при использовании вместе с select new map:

Блок кода
languagesql
select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
from Cat cat

Этот запрос возвращает Map из псевдонимов выбранных значений.

Агригатные функции

Запросы HQL могут даже возвращать результаты агрегатных функций по свойствам:

Блок кода
languagesql
select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
from Cat cat

Поддерживаемые агрегированные функции:

  • avg(...), sum(...), min(...), max(...)
  • count(*)
  • count(...), count(distinct ...), count(all...)

Вы можете использовать арифметические операторы, конкатенацию и известные функции SQL в секции select:

Блок кода
languagesql
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

Ключевые слова distinct и all могут использоваться и имеют ту же семантику, что и в SQL.

Блок кода
languagesql
select distinct cat.name from Cat cat

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

Полиморфные запросы

Запросы вида:

Блок кода
languagesql
from Cat as cat

возвращают экземпляры не только Cat, но и подклассов, таких как DomesticCat. Запросы Hibernate могут называть любой класс или интерфейс Java в секции from. Запрос вернет экземпляры всех постоянных классов, которые расширяют этот класс или реализуют интерфейс. Следующий запрос будет возвращать все постоянные объекты:

Блок кода
languagesql
from java.lang.Object o

Интерфейс Named может быть реализован различными постоянными классами:

Блок кода
languagesql
from Named n, Named m where n.name = m.name

Этим двум запросам потребуются более одного SQL SELECT. Это означает, что секция order by неверно упорядочивает весь набор результатов. Это также означает, что вы не можете вызывать эти запросы с помощью Query.scroll().

Секция «where»

Предложение where позволяет уточнить список возвращаемых экземпляров. Если псевдоним не существует, вы можете ссылаться на свойства по имени:

Блок кода
languagesql
from Cat where name='Fritz'

Если есть псевдоним, используйте квалифицированное имя свойства:

Блок кода
languagesql
from Cat as cat where cat.name='Fritz'

Этот запрос возвращает экземпляры Cat с именем «Fritz».

Следующий запрос:

Блок кода
languagesql
select foo
from Foo foo, Bar bar
where foo.startDate = bar.date

возвращает все экземпляры Foo с экземпляром bar с свойством date, равным свойству startDate для Foo. Сложные выражения делают секцию where чрезвычайно мощной. Рассмотрим следующее:

Блок кода
languagesql
from Cat cat where cat.mate.name is not null

Этот запрос переводится в SQL-запрос с табличным (внутренним) соединением. Например:

Блок кода
languagesql
from Foo foo
where foo.bar.baz.customer.address.city is not null

приведет к запросу, который потребует объединения четырёх таблиц в SQL.

Оператор = можно использовать для сравнения не только свойств, но и экземпляров:

Блок кода
languagesql
from Cat cat, Cat rival where cat.mate = rival.mate
select cat, mate
from Cat cat, Cat mate
where cat.mate = mate

Специальное свойство (нижний регистр) id может использоваться для ссылки на уникальный идентификатор объекта. Дополнительную информацию см. в разделе Ссылаясь на свойство идентификатора

Блок кода
languagesql
from Cat as cat where cat.id = 123

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

Второй запрос эффективен и не требует соединения таблиц.

Также можно использовать свойства составных идентификаторов. Рассмотрим следующий пример, в котором у Person есть составные идентификаторы, состоящие из country и medicareNumber:

Блок кода
languagesql
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

Еще раз, второй запрос не требует соединения таблиц.

См. раздел Ссылаясь на свойство идентификатора для получения дополнительной информации о ссылках на свойства идентификатора).

Специальный свойство class обращается к значению дискриминатора экземпляра в случае полиморфного постоянства (polymorphic persistence). Имя класса Java, встроенное в секцию where, будет переведено на его значение дискриминатора.

Блок кода
languagesql
from Cat cat where cat.class = DomesticCat

Вы также можете использовать компоненты, или составные пользователбские типы, или свойства указанных типов компонентов. Дополнительную информацию см. в разделе Компоненты

«Любой» тип имеет специальные свойства id и class, которые позволяют вам выразить объединение следующим образом (где AuditLog.item — это свойство, отображаемое в <any>):

Блок кода
languagesql
from AuditLog log, Payment payment
where log.item.class = 'Payment' and log.item.id = payment.id

Класс log.item.class и payment.class будут ссылаться на значения полностью разных столбцов базы данных в вышеуказанном запросе.

Выражения

Выражения, используемые в предложении where, включают следующее:

  • математические операторы: +, -, *, /
  • двоичные операторы сравнения: =, >=, <=, <>, !=, like
  • логические операции: and, or, not
  • скобки ( ), которые указывают на группировку
  • in, not in, between, is null, is not null, is empty, is not empty, member of и not member of
  • «Простые» case: case ... when ... then ... else ... end и «поисковые» case: case when ... then ... else ... end
  • сравнение строк ...||... или concat(...,...)
  • current_date(), current_time() и current_timestamp()
  • second(...), minute(...), hour(...), day(...), month(...), and year(...)
  • Любая функция или оператор, определенные EJB-QL 3.0: substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()
  • coalesce() и nullif()
  • str() для преобразования числовых или временных значений в читаемую строку
  • cast (... as ...), где второй аргумент — это имя типа Hibernate и extract (... from ...), если ANSI cast() и extract() поддерживается базой данных.
  • функция HQL index(), которая применяется к псевдонимам объединённой индексированной коллекции.
  • HQL-функции, которые принимают выражения, связанные с коллекцией: size(), mylement(), maxelement(), minindex(), maxindex(), а также специальные э elements() и функции indices, которые могут быть количественно определены с использованием some, all, exists, any, in.
  • Любая скалярная функция SQL с поддержкой базы данных типа: sign(), trunc(), rtrim(), and sin()
  • Позиционные параметры JDBC-стиля ?
  • именованные параметры: :name, :start_date и :x1
  • SQL литералы: 'foo', 69, 6.66E+2, '1970-01-01 10:00:01.0'
  • Java public static final константы eg.Color.TABBY

in и between может использоваться следующим образом:

Блок кода
languagesql
from DomesticCat cat where cat.name between 'A' and 'B'

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

Отрицательные формы можно записать следующим образом:

Блок кода
languagesql
from DomesticCat cat where cat.name not between 'A' and 'B'

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

Аналогичным образом, is null и is not null могут быть использованы для проверки нулевых значений.

Булевы могут быть легко использованы в выражениях, объявлением в конфигурации Hibernate для подстановки HQL-запросов:

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

Это заменит ключевые слова true и false литералами 1 и 0при трансляции из  HQL в SQL:

Блок кода
languagesql
from Cat cat where cat.alive = true

Вы можете проверить размер коллекции специальным свойством size или специальной функцией size().

Блок кода
languagesql
from Cat cat where cat.kittens.size > 0

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

Для индексированных коллекций вы можете ссылаться на минимальный и максимальный индексы, используя функции minindex и maxindex. Аналогично, вы можете ссылаться на минимальный и максимальный элементы коллекции базового типа, используя функции minelement и maxelement. Например:

Блок кода
languagesql
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

Функции SQL any, some, all, exist, in поддерживаются при передаче элемента или набора индексов коллекции (функции elements и indices) или результата подзапроса (см. ниже):

Блок кода
languagesql
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)

Обратите внимание, что эти конструкции — size, elements, indices, minindex, maxindex, minelement, maxelement — могут использоваться только в секции where в Hibernate.

Элементы индексированных коллекций (массивы, списки и карты) могут упоминаться только индексом в секции where:

Блок кода
languagesql
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

Выражение внутри [] может быть даже арифметическим выражением:

Блок кода
languagesql
select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item

HQL также предоставляет встроенную функцию index() для элементов ассоциации «один-ко-многим» или коллекции значений.

Блок кода
languagesql
select item, index(item) from Order order
    join order.items item
where index(item) < 5

Скалярные функции SQL, поддерживаемые базой данных, могут быть использованы:

Блок кода
languagesql
from DomesticCat cat where upper(cat.name) like 'FRI%'

Подумайте, насколько длиннее и менее читаемым мог бы быть следующий запрос на SQL:

Блок кода
languagesql
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)

Подсказка: что-то вроде

Блок кода
languagesql
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
    )

Секция «order by»

Список, возвращаемый запросом, может быть упорядочен любым свойством возвращаемого класса или компонента:

Блок кода
languagesql
from DomesticCat cat
order by cat.name asc, cat.weight desc nulls first, cat.birthdate

Необязательный asc или desc указывают соответственно на восходящий или нисходящий порядок.

Необязательные nulls first или nulls last указывают приоритет значений null при сортировке.

Секция «group by»

Запрос, возвращающий агрегированные значения, может быть сгруппирован любым свойством возвращаемого класса или компонента:

Блок кода
languagesql
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

Секция having также разрешена.

Блок кода
languagesql
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)

Функции SQL и агрегированные функции разрешены в секциях having и order by, если они поддерживаются базой данных (например в MySQL их нет).

Блок кода
languagesql
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

Ни секция group by, ни секция order by не могут содержать арифметические выражения. Также, в настоящее время, Hibernate не расширяет сгруппированную сущность, поэтому вы не можете писать group by cat, если все свойства cat не агрегированы. Вы должны явно указать все неагрегированные свойства.

Подзапросы

Для баз данных, которые поддерживают подзапросы, Hibernate поддерживает подзапросы внутри запросах. Подзапрос должен быть окружен скобками (часто с помощью вызова агреганой функции SQL). Разрешены даже коррелированные подзапросы (подзапросы, которые ссылаются на псевдонимы во внешнем запросе).

Блок кода
languagesql
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
)


Обратите внимание, что подзапросы HQL могут встречаться только в секциях select или where.

Обратите внимание, что в подзапросах также может использоваться синтаксис row value constructor. Дополнительную информацию см. в разделе Синтаксис конструктора значения записи

Советы и хитрости

Вы можете подсчитать количество результатов запроса, не возвращая их:

Блок кода
languagejava
( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue()

Чтобы упорядочить результат по размеру коллекции, используйте следующий запрос:

Блок кода
languagesql
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)

Если ваша база данных поддерживает подзапросы, вы можете поместить условие на размер выбора в секцию where вашего запроса:

Блок кода
languagesql
from User usr where size(usr.messages) >= 1

Если ваша база данных не поддерживает подзапросы, используйте следующий запрос:

Блок кода
languagesql
select usr.id, usr.name
from User usr
    join usr.messages msg
group by usr.id, usr.name
having count(msg) >= 1

Поскольку это решение не может вернуть User с нулём сообщений из-за внутреннего соединения, следующая форма также полезна:

Блок кода
languagesql
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

Свойства JavaBean могут быть привязаны к именованным параметрам запроса:

Блок кода
languagejava
Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
q.setProperties(fooBean); // fooBean имеет getName() и getSize()
List foos = q.list();

Коллекции можно просмотреть с помощью интерфейса Query с фильтром:

Блок кода
languagejava
Query q = s.createFilter( collection, "" ); // тривиальный фильтр
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();

Элементы коллекции можно упорядочить или сгруппировать с помощью фильтра запросов:

Блок кода
languagejava
Collection orderedCollection = s.filter( collection, "order by this.amount" );
Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );

Вы можете найти размер коллекции без ее инициализации:

Блок кода
languagesql
( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue();

Компоненты

Компоненты могут использоваться аналогично простым типам значений, которые используются в запросах HQL. Они могут отображаться в секции следующим образом:

Блок кода
languagesql
select p.name from Person p

select p.name.first from Person p

где свойство имени Person является компонентом. Компоненты также могут использоваться в секции where:

Блок кода
languagesql
from Person p where p.name = :name

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

Компоненты также могут использоваться в секции order by:

Блок кода
languagesql
from Person p order by p.name

from Person p order by p.name.first

Другое распространенное использование компонентов приведено в разделе Синтаксис конструктора значения записи

Синтаксис конструктора значения записи

HQL поддерживает использование синтаксиса конструктора значений записи (row value constructor) ANSI SQL, иногда называемого синтаксисом AS tuple, хотя база данных может не поддерживать это понятие. Здесь мы обычно ссылаемся на многозначные сравнения, обычно связанные с компонентами. Рассмотрим сущность Person, которая определяет компонент имени:

Блок кода
languagesql
from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt'

Это допустимый синтаксис, хотя он немного избыточный. Вы можете сделать его более кратким, используя синтаксис конструктора значения записи:

Блок кода
languagesql
from Person p where p.name=('John', 'Jingleheimer-Schmidt')

Также может быть полезно указать это в секции select:

Блок кода
languagesql
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
)

Одна вещь, которую следует учитывать при принятии решения о том, хотите ли вы использовать этот синтаксис, заключается в том, что запрос будет зависеть от порядка под-свойств компонента в метаданных.