
- •Обозначения и сокращения
- •введение
- •1. Установка и настройка инструментальных средств
- •1.1. Установка и подготовка к работе операционной системы
- •1.2. Установка программного обеспечения
- •1.3. Создание таблиц в базе данных
- •2. Основы Java EE 6
- •2.1. Распределенные многоуровневые приложения
- •2.2. Контейнеры Java EE
- •2.3. Сервер GlassFish v3
- •2.4. Структура приложения
- •2.5. Конфигурирование приложений
- •2.6. Задание ссылок на ресурсы
- •4. Введение в компоненты Facelets
- •4.1. Веб-страницы
- •4.2. Разработка простого приложения Facelets
- •4.3. Использование шаблонов
- •5. Унифицированный язык записи выражений
- •6.1. Добавление компонент библиотеки HTML на страницу
- •6.2. Использование компонент для таблиц баз данных
- •6.3. Использование тегов библиотеки Core
- •7. Использование конвертеров, слушателей и проверок
- •7.1. Использование стандартных преобразователей
- •7.2. Регистрация слушателей для компонентов
- •8. Внешние объекты (JavaBeans)
- •8.1. Создание класса внешних объектов
- •8.2. Описание свойств бинов
- •8.3. Написание методов внешних бинов
- •8.4. Проверка бинами
- •9.1. Файл конфигурации ресурсов приложения
- •9.2. Упорядочение ресурсов конфигурации приложения
- •9.3. Конфигурирование состояния проекта
- •9.4. Выбор конфигурации бина
- •9.5. Регистрация сообщений об ошибках как пакет ресурса
- •9.7. Конфигурирование правил навигации (Navigation Rules)
- •9.8. Основные требования приложения JavaServer Faces
- •10. Технология Java Servlet
- •11. Введение в Java Persistence API
- •11.1. Требования к классам сущностей
- •11.3. Внедряемые классы в сущностях
- •11.4. Наследование сущностей
- •11.5. Стратегии наследования сущностей с отображением
- •11.6. Управление сущностями
- •11.7. Запросы сущностей
- •12. Примеры хранимых сущностей
- •12.1. Приложение order
- •12.2. Пример получения схемы отношений на основе таблиц БД
- •13.1. Терминология языка запросов
- •13.3. Упрощенный синтаксис языка запросов
- •13.4. Примеры запросов
- •13.5. Запросы с навигацией связанных сущностей
- •13.6. Запросы с другими условными выражениями
- •13.7. Изменение и удаление группы сущностей
- •13.8. Полный синтаксис языка запросов
- •14. Язык запросов Criteria API
- •14.3. Корни запроса
- •14.4. Использование объединения в запросе
- •14.5. Навигация путей в запросах
- •14.6. Ограничения на результаты запроса
- •14.7. Управление результатами запросов
- •14.8. Исполнение запросов
- •15. Связывание ресурсов
- •15.1. Ресурсы и служба имен JNDI
- •15.2. Объекты DataSource и пулы соединений (Connection Pools)
- •15.3. Внедрение ресурсов
- •15.4. Адаптеры ресурсов
- •15.5. Аннотации метаданных
- •16. Безопасность веб-приложений
- •16.1. Краткий обзор
- •16.2. Механизмы обеспечения безопасности
- •16.3. Безопасность сервера предприятия
- •16.4. Использование защищенного соединения SSL
- •18. Пример приложения
- •18.1. Создание проекта веб-приложения
- •18.3.Структура приложения JavaEE 6
- •18.4. Программирование вида для объектов
- •18.5. Дизайн главной страницы
- •18.6. Страница просмотра записей таблицы городов
- •18.7. Страница добавления записей о городах
- •18.8. Страница редактирования записей о городах
- •18.9. Страница удаления записей о городах
- •19. Обработка связей внешних ключей
- •19.1. Разработка класса для вида сущности
- •19.2. Доработка вида для городов
- •19.3. Разработка обзорной страницы
- •19.5. Страница для редактирования записей с внешними ключами
- •20. Дополнительные функции
- •20.1. Сортировка записей таблицы
- •20.2. Контроль за удалением связанных записей
- •20.3. Контроль ввода наименований
- •20.4. Запросы к БД на языке Java Persistence Query Language
- •20.5. Управление страницами при просмотре таблицы
- •20.6. Создание и просмотр отчетов
- •20.7. Использование шаблонов и стилей
- •20.8. Защита приложения паролем
- •Заключение
- •Библиографический список
Управление согласно полям связи
SELECT DISTINCT p
FROM Player p, IN (p.teams) t WHERE t.league.sport = :sport
Результат: игроки, которые участвуют в определённом спорте.
Описание:хранимаяобластьспортапринадлежитсущностиLeague.Чтобыдостичь поля sport, запрос должен сначала перейти от сущности Player до Team (p.teams) и затем от Team до сущности League (t.league). Поскольку поле league отношения не является коллекцией, оно может следовать за хранимым полем sport.
13.6.Запросы с другими условными выражениями
Каждая статья WHERE может определить условное выражение в нескольких вариантах. В предшествующих примерах условные выражения являются выражениями сравнения, которые тестируются на равенство. Следующие примеры демонстрируют некоторые другие варианты условных выражений.
Запросы LIKE
SELECT p
FROM Player p
WHERE p.name LIKE ’Mich%’
Результат: все игроки, чьи имена начинают с Mich.
Описание: выражение LIKE использует символы шаблона, чтобы искать строки, которые соответствуют образцу. В этом случае запрос использует выражение LIKE и шаблон «%», чтобы находить всех игроков, чьи имена начинаются со строки Mich. Например, имена Michael и Michelle оба соответствуют образцу шаблона.
Выражение IS NULL
SELECT t FROM Team t
WHERE t.league IS NULL
Результат: все команды, не связанные с лигой.
Описание: выражение IS NULL может быть использовано, чтобы проверять, установлено ли отношение между двумя сущностями. В этом случае запрос проверяет команды, связанные с любыми лигами, и возвращает команды, которые не входят в лигу.
Выражение IS EMPTY
SELECT p FROM Player p
WHERE p.teams IS EMPTY
Результат: все игроки, не принадлежащие командам.
Описание: поле teams отношения сущности Player является коллекцией. Если игрок не принадлежит команде, тогда коллекция teams будет пустой, условным выра-
жением является TRUE.
156
Выражение BETWEEN
SELECT DISTINCT p FROM Player p
WHERE p.salary BETWEEN :lowerSalary AND :higherSalary
Результат: игроки, чей фонд зарплаты находится в пределах определённого диапазона.
Описание: это выражение BETWEEN имеет три арифметических выражения: хранимое поле (p.salary) и два входных параметра (:lowerSalary и :higherSalary). Следующее выражение является эквивалентом BETWEEN выражению:
p.salary >= :lowerSalary AND p.salary <= :higherSalary
Операторы сравнения
SELECT DISTINCT p1
FROM Player p1, Player p2
WHERE p1.salary > p2.salary AND p2.name = :name
Результат: все игроки, чей фонд зарплаты выше, чем жалованье игрока с определённым именем.
Описание: статья FROM объявляет две переменные (p1 и p2) того же самого типа (Player). Две переменных нужны, поскольку статья WHERE сравнивает жалованье одного игрока (p2) с другими игроками (p1).
13.7.Изменение и удаление группы сущностей
Следующие примеры показывают, как использовать выражения UPDATE и DELETE в запросах. UPDATE и DELETE действуют на многие сущности согласно условию, установленному в статье WHERE. Статья WHERE в запросе UPDATE и DELETE следует тем же правилам, что и в запросе SELECT.
Запрос UPDATE
UPDATE Player p
SET p.status = ’inactive’
WHERE p.lastPlayed < :inactiveThresholdDate
Описание: этот запрос устанавливает статус множества игроков как неактивный, если последняя игра была ранее, чем дата в inactiveThresholdDate.
Запрос DELETE
DELETE
FROM Player p
WHERE p.status = ’inactive’ AND p.teams IS EMPTY
Описание: Этот запрос удаляет всех неактивных игроков, которые не зачислены в команды.
157
13.8.Полный синтаксис языка запросов
Вданном разделе описывается синтаксис языка запроса, как определено в спецификации Java Persistence.
13.8.1.Символы BNF
|
Таблица 13.1 |
|
|
Символ |
Описание |
::= |
Элемент слева от символа определен справа |
* |
Выражение слева может входить нуль или более раз |
{...} |
Конструкция в пределах фигурных скобок образует группу |
[...] |
Конструкция в пределах квадратных скобок не обязательная |
| |
Исключительное ИЛИ |
ЖИРНЫЙ |
Ключевое слово (заглавные буквы на диаграмме BNF, |
шрифт |
не регистро-чувствительные ключевые слова) |
Интервал |
Символ интервала может быть пробелом, горизонтальной |
|
табуляцией или переводом строки |
13.8.2. BNF-грамматика языка Java Persistence Query Language
Полная диаграмма BNF для языка запросов
QL_statement ::= select_statement | update_statement | delete_statement
select_statement ::= select_clause from_clause [where_clause] [groupby_clause]
[having_clause] [orderby_clause] update_statement ::= update_clause [where_clause] delete_statement ::= delete_clause [where_clause] from_clause ::=
FROM identification_variable_declaration
{, {identification_variable_declaration | collection_member_declaration}}*
identification_variable_declaration ::= range_variable_declaration { join | fetch_join }*
range_variable_declaration ::= abstract_schema_name [AS] identification_variable
join ::= join_spec join_association_path_expression [AS] identification_variable
fetch_join ::= join_specFETCH join_association_path_expression association_path_expression ::=
collection_valued_path_expression | single_valued_association_path_expression
join_spec::= [LEFT [OUTER] |INNER] JOIN join_association_path_expression ::=
join_collection_valued_path_expression | join_single_valued_association_path_expression
join_collection_valued_path_expression::=
158
identification_variable.collection_valued_association_field join_single_valued_association_path_expression::=
identification_variable.single_valued_association_field collection_member_declaration ::=
IN (collection_valued_path_expression) [AS] identification_variable
single_valued_path_expression ::= state_field_path_expression | single_valued_association_path_expression
state_field_path_expression ::= {identification_variable |
single_valued_association_path_expression}.state_field single_valued_association_path_expression ::=
identification_variable.{single_valued_association_field.}* single_valued_association_field
collection_valued_path_expression ::= identification_variable.{single_valued_association_field.}* collection_valued_association_field
state_field ::= {embedded_class_state_field.}*simple_state_field
update_clause ::=UPDATE abstract_schema_name [[AS] identification_variable] SET update_item {, update_item}*
update_item ::= [identification_variable.]{state_field | single_valued_association_field} = new_value
new_value ::= simple_arithmetic_expression | string_primary | datetime_primary | boolean_primary |
enum_primary simple_entity_expression | NULL
delete_clause ::= DELETE FROM abstract_schema_name [[AS] identification_variable]
select_clause ::= SELECT [DISTINCT] select_expression {, select_expression}*
select_expression ::= single_valued_path_expression | aggregate_expression | identification_variable | OBJECT(identification_variable) | constructor_expression
constructor_expression ::=
NEW constructor_name(constructor_item {, constructor_item}*)
constructor_item ::= single_valued_path_expression | aggregate_expression
aggregate_expression ::=
{AVG |MAX |MIN |SUM} ([DISTINCT] state_field_path_expression) |
COUNT ([DISTINCT] identification_variable | state_field_path_expression |
159
single_valued_association_path_expression) where_clause ::= WHERE conditional_expression groupby_clause ::= GROUP BY groupby_item {, groupby_item}* groupby_item ::= single_valued_path_expression having_clause ::= HAVING conditional_expression orderby_clause ::= ORDER BY orderby_item {, orderby_item}* orderby_item ::= state_field_path_expression [ASC |DESC] subquery ::= simple_select_clause subquery_from_clause
[where_clause] [groupby_clause] [having_clause] subquery_from_clause ::=
FROM subselect_identification_variable_declaration
{, subselect_identification_variable_declaration}* subselect_identification_variable_declaration ::=
identification_variable_declaration | association_path_expression [AS] identification_variable | collection_member_declaration
simple_select_clause ::= SELECT [DISTINCT] simple_select_expression
simple_select_expression::= single_valued_path_expression | aggregate_expression | identification_variable
conditional_expression ::= conditional_term | conditional_expression OR conditional_term
conditional_term ::= conditional_factor | conditional_term AND conditional_factor
conditional_factor ::= [NOT] conditional_primary conditional_primary ::= simple_cond_expression |(
conditional_expression) simple_cond_expression ::= comparison_expression |
between_expression | like_expression | in_expression | null_comparison_expression |
empty_collection_comparison_expression | collection_member_expression | exists_expression
between_expression ::= arithmetic_expression [NOT] BETWEEN
arithmetic_expressionAND arithmetic_expression | string_expression [NOT] BETWEEN string_expression AND
string_expression | datetime_expression [NOT] BETWEEN
datetime_expression AND datetime_expression in_expression ::=
state_field_path_expression [NOT] IN (in_item {, in_item}* | subquery)
in_item ::= literal | input_parameter like_expression ::=
string_expression [NOT] LIKE pattern_value [ESCAPE
160
escape_character] null_comparison_expression ::=
{single_valued_path_expression | input_parameter} IS [NOT] NULL
empty_collection_comparison_expression ::= collection_valued_path_expression IS [NOT] EMPTY
collection_member_expression ::= entity_expression [NOT] MEMBER [OF] collection_valued_path_expression
exists_expression::= [NOT] EXISTS (subquery) all_or_any_expression ::= {ALL |ANY |SOME} (subquery) comparison_expression ::=
string_expression comparison_operator {string_expression | all_or_any_expression} |
boolean_expression {= |<> } {boolean_expression | all_or_any_expression} |
enum_expression {= |<> } {enum_expression | all_or_any_expression} | datetime_expression comparison_operator
{datetime_expression | all_or_any_expression} | entity_expression {= |<> } {entity_expression | all_or_any_expression} |
arithmetic_expression comparison_operator
{arithmetic_expression | all_or_any_expression} comparison_operator ::= = |> |>= |< |<= |<> arithmetic_expression ::= simple_arithmetic_expression |
(subquery) simple_arithmetic_expression ::=
arithmetic_term | simple_arithmetic_expression {+ |- } arithmetic_term
arithmetic_term ::= arithmetic_factor | arithmetic_term {* |/ } arithmetic_factor
arithmetic_factor ::= [{+ |- }] arithmetic_primary arithmetic_primary ::=
state_field_path_expression | numeric_literal | (simple_arithmetic_expression) | input_parameter | functions_returning_numerics | aggregate_expression
string_expression ::= string_primary | (subquery) string_primary ::=
state_field_path_expression | string_literal | input_parameter | functions_returning_strings | aggregate_expression
datetime_expression ::= datetime_primary | (subquery) datetime_primary ::=
state_field_path_expression | input_parameter | functions_returning_datetime |
161
aggregate_expression
boolean_expression ::= boolean_primary | (subquery) boolean_primary ::=
state_field_path_expression | boolean_literal | input_parameter
enum_expression ::= enum_primary | (subquery) enum_primary ::=
state_field_path_expression | enum_literal | input_parameter
entity_expression ::= single_valued_association_path_expression |
simple_entity_expression simple_entity_expression ::=
identification_variable | input_parameter
functions_returning_numerics::= LENGTH(string_primary) | LOCATE(string_primary, string_primary[,
simple_arithmetic_expression]) | ABS(simple_arithmetic_expression) | SQRT(simple_arithmetic_expression) | MOD(simple_arithmetic_expression,
simple_arithmetic_expression) | SIZE(collection_valued_path_expression)
functions_returning_datetime ::= CURRENT_DATE |
CURRENT_TIME |
CURRENT_TIMESTAMP functions_returning_strings ::=
CONCAT(string_primary, string_primary) | SUBSTRING(string_primary,
simple_arithmetic_expression, simple_arithmetic_expression)|
TRIM([[trim_specification] [trim_character] FROM] string_primary) |
LOWER(string_primary) |
UPPER(string_primary)
trim_specification ::= LEADING | TRAILING | BOTH
Статья FROM определяет область запроса, объявляя идентификаторы пере-
менных.
Идентификаторы
Идентификатор—последовательностьодногоилиболеесимволов.Первыйсим-
вол должен быть правильным (буква, $, _) в языке программирования Java. Каждый по-
следующий символ в последовательности должен быть правильным символом (буква, цифра, $, _) в идентификаторе Java. Знак вопроса (?) — зарезервированный символ в языке запросов и не может быть использован в идентификаторе. Идентификаторы запроса — регистро-чувствительные с двумя исключениями, касающимися ключевых слов языка запросов и SQL.
162
Ключевые слова
Идентификатор не может быть таким же, как ключевое слово языка запроса.
Список ключевых слов языка запроса
ABS |
ALL |
AND |
ANY |
AS |
ASC |
AVG |
BETWEEN |
BIT_LENGTH |
BOTH |
BY |
CASE |
CHAR_LENGTH |
CHARACTER_LENGTH |
CLASS |
COALESCE |
CONCAT |
COUNT |
CURRENT_DATE |
CURRENT_TIMESTAMP |
DELETE |
DESC |
DISTINCT |
ELSE |
EMPTY |
END |
ENTRY |
ESCAPE |
EXISTS |
FALSE |
FETCH |
FROM |
GROUP |
HAVING |
IN |
INDEX |
INNER |
IS |
JOIN |
KEY |
LEADING |
LEFT |
LENGTH |
LIKE |
LOCATE |
LOWER |
MAX |
MEMBER |
MIN |
MOD |
NEW |
NOT |
NULL |
NULLIF |
OBJECT |
OF |
OR |
ORDER |
OUTER |
POSITION |
SELECT |
SET |
SIZE |
SOME |
SQRT |
SUBSTRING |
SUM |
THEN |
TRAILING |
TRIM |
TRUE |
TYPE |
UNKNOWN |
UPDATE |
UPPER |
VALUE |
WHEN |
WHERE |
|
|
Не рекомендуется использовать ключевые слова языка SQL как идентификаторы, поскольку список ключевых слов может расшириться, чтобы в будущем включить другие резервные слова SQL.
13.8.3. Идентификационные переменные отношений
Идентификационная переменная отношения (псевдоним) является идентификатором, объявленным в статье FROM. Хотя статьи SELECT и WHERE могут ссылаться на переменные идентификации, они не могут объявить их. Все переменные идентификации должны быть объявлены в статье FROM.
Поскольку переменная идентификации является идентификатором, она имеет стандартные соглашения и ограничения о присваивании имен. Например, переменная идентификации не может быть такой же, как и ключевое слово языка запроса. Также, в пределах данного устройства хранения, имя переменной идентификации не должно соответствовать имени любой сущности или абстрактной схемы.
Статья FROM может содержать несколько деклараций, разделенных запятыми. Декларация может ссылаться на другую переменную идентификации, которая объявлена прежде (слева). В следующей статье FROM переменная t ссылается на прежде
объявленную переменную p:
FROM Player p, IN (p.teams) AS t
Даже если переменная идентификации не была использована в статье WHERE, декларации могут повлиять на результаты запроса. Для примера сравните следующие
163
два запроса. Первый запрос возвращает всех игроков, принадлежащих или не принадлежащих команде:
SELECT p FROM Player p
Для контраста, поскольку следующий запрос объявляет переменную идентифи-
кации t, он выбирает всех игроков, которые принадлежат команде:
SELECT p
FROM Player p, IN (p.teams) AS t
Второй запрос возвращает те же результаты, что и предыдущий запрос, но ста-
тья WHERE делает его легче для понимания:
SELECT p FROM Player p
WHERE p.teams IS NOT EMPTY
Переменная идентификации всегда определяет ссылку на единственное значе-
ние, чей тип является тем самым выражением, использованным в декларации. Есть
два типа деклараций: переменная диапазона (Range Variable) и элемент коллекции.
Декларации Range Variable
Чтобы объявлять переменную идентификации как абстрактный тип схемы, вы
определяете переменную декларацию диапазона. Другими словами, переменная идентификации может охватывать абстрактный тип схемы сущности. В следующем
примере переменная идентификации p представляет абстрактную схему с именем
Player:
FROM Player p
Переменная декларация диапазона может включить дополнительный оператор AS:
FROM Player AS p
В большинстве случаев, чтобы получить объекты, вы используете выражения
навигации для отношения. Для сущностей, которые не могут быть получены навигацией, можно использовать переменную декларации диапазона, чтобы обозначить отправной пункт (или корень).
Если запрос сравнивает многочисленные значения той же самой абстрактной
схемы, тогда статья FROM должна объявить многочисленные переменные идентифи-
кации для абстрактной схемы, например:
FROM Player p1, Player p2
Декларации элемента коллекции
В отношении «один-ко-многим» множественная сторона состоит из коллекции
сущностей. Переменная идентификации может представить элемент этого набора. Для того, чтобы иметь доступ к элементу набора, выражение пути в декларации пере-
менной включает переходы через отношения в абстрактной схеме. Поскольку выра-
жение пути может быть основано на другом выражении пути, навигация может про-
смотреть несколько связей.
Декларация элемента коллекции должна включать оператор IN, но можно опу-
стить дополнительный оператор AS.
В следующем примере сущность представляется абстрактной схемой Player и
имеет поле отношения с именем teams. Переменная идентификации была названа t и представляет единственный элемент набора teams.
FROM Player p, IN (p.tea ms) t
164
Присоединения
Оператор JOIN используется для обзора связей между сущностями и функцио-
нально подобен оператору IN.
В следующем примере запрос соединяет отношения между клиентами и заказами:
SELECT c
FROM Customer c JOIN c.orders o
WHERE c.status = 1 AND o.totalPrice > 10000
Ключевое слово INNER дополнительное:
SELECT c
FROM Customer c INNER JOIN c.orders o WHERE c.status = 1 AND o.totalPrice > 10000
Эти примеры эквивалентны следующему запросу, который использует опе-
ратор IN:
SELECT c
FROM Customer c, IN(c.orders) o
WHERE c.status = 1 AND o.totalPrice > 10000
Вы можете также соединять однозначные отношения, например:
SELECT t
FROM Team t JOIN t.league l WHERE l.sport = :sport
LEFT JOIN или LEFT OUTER JOIN извлекает множество сущностей, которые
сопоставляются значениям в условии объединения, которое может и отсутствовать. Ключевое слово OUTER (внешнее) — дополнительное.
SELECT c.name, o.totalPrice
FROM Order o LEFT JOIN o.customer c
FETCH JOIN является операцией соединения, которая возвращает связанные
сущности как побочный эффект исполнения запроса. В следующем примере запрос возвращает набор отделов и, как побочный эффект, служащих отделов, даже если служащие явно не были извлечены статьей SELECT.
SELECT d
FROM Department d LEFT JOIN FETCH d.employees WHERE d.deptno = 1
13.8.4. Выражения пути
Выражения пути — важная часть синтаксиса языка запросов. Во-первых, они
определяют навигацию через отношения в абстрактных схемах. Эта часть определяет
результирующую область просмотра и результат запроса. Во-вторых, они появляются в основных операторах запроса SELECT, DELETE, HAVING, UPDATE, WHERE, FROM,
GROUP BY, ORDER BY. Наконец, хотя язык запросов и является подмножеством язы-
ка SQL, выражений пути в SQL нет.
Примеры выражений пути
В примере, приведенном ниже, статья WHERE содержит single_valued_path_ expression. Переменная p и salary — хранимые поля сущности Player:
SELECT DISTINCT p FROM Player p
WHERE p.salary BETWEEN :lowerSalary AND :higherSalary
165
Ниже статья WHERE содержит single_valued_path_expression. Переменная t
и league — отношения single-valued, переменная sport — хранимое поле отношения league.
SELECT DISTINCT p
FROM Player p, IN (p.teams) t WHERE t.league.sport = :sport
Ниже статья WHERE содержит collection_valued_path_expression. Переменная p — идентифицирующая переменная, а teams обозначает поле collection-valued relationship.
SELECT DISTINCT p FROM Player p
WHERE p.teams IS EMPTY
Типы выражений
Тип выражений пути является типом объекта, представленным конечным эле-
ментом, который может быть:
•хранимым полем;
•полем отношения с одним значением (Single-valued);
•полем отношения с коллекцией значений (Collection-valued).
Например, тип выражения p.salary — double, потому что тип последнего поля salary есть double.
В выражении p.teams последний элемент — коллекция, поэтому тип выражения — коллекция сущностей.
Навигация
Выражение пути позволяет производить навигацию по сущностям отношения.
Последний элемент выражения определяет разрешенную навигацию. Если выражение содержит поле отношения Single-valued, просматриваются объекты, указываемые полем. Однако выражения не могут просматривать хранимые поля или поля коллек-
ций Collection-valued. Например, выражение p.teams.league.sport — правильное, так
как teams — поле отношения Collection-valued. Для указания поля sport статья FROM
может определить переменную идентификации с именем t для поля teams.
FROM Player AS p, IN (p.teams) t WHERE t.league.sport = ’soccer’
13.8.5. Статья WHERE
ОпцияWHERE задаётусловноевыражение,ограничивающеезначения,возвращаемые запросом. Запрос возвращает все значения, соответствующие истинному вы-
ражению. Если статья WHERE отсутствует, то возвращаются все значения. Синтаксис
опции WHERE следующий:
where_clause ::= WHERE conditional_expression
В условном выражении можно использовать все типы допустимых в языке
литералов: String, numeric, Boolean, Enum. Можно использовать именованные и позиционные параметры, все допустимые в Java арифметические и логические опе-
рации и сравнения аргументов. Кроме простых условий, можно использовать опера-
ции LIKE, BETWEEN и IN. Для проверки на пустое множество используется операция
IS EMPTY.
SELECT o
FROM Order o
WHERE o.lineItems IS EMPTY
166
Для проверки принадлежности множеству есть операция MEMBER OF, например:
SELECT o
FROM Order o
WHERE :lineItem MEMBER OF o.lineItems
Допускается использовать запросы в условиях:
SELECT c
FROM Customer c
WHERE (SELECT COUNT(o) FROM c.orders o) > 10
SELECT DISTINCT emp
FROM Employee emp
WHERE EXISTS (
SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
SELECT emp
FROM Employee emp
WHERE emp.salary > ALL ( SELECT m.salary FROM Manager m
WHERE m.department = emp.department)
В табл. 13.2 определены функции различных типов.
Таблица 13.2
Функции языка запросов |
|
|
|
|
|
Функция |
Возвращаемое |
|
значение |
||
|
||
CONCAT(String, String) |
String |
|
LENGTH(String) |
Int |
|
LOCATE(String, String [, start]) |
int |
|
SUBSTRING(String, start, length) |
String |
|
TRIM([[LEADING|TRAILING|BOTH] char) FROM] (String) |
String |
|
LOWER(String) |
String |
|
UPPER(String) |
String |
|
|
|
|
ABS(number) |
int, float, or double |
|
MOD(int, int) |
int |
|
SQRT(double) |
double |
|
SIZE(Collection) |
int |
|
|
|
|
CURRENT_DATE |
java.sql.Date |
|
CURRENT_TIME |
java.sql.Time |
|
CURRENT_TIMESTAMP |
java.sql.Timestamp |
167
Выражение CASE
Выражение CASE аналогично оператору CASE языка Java и позволяет произ-
водить множественный выбор возвращаемых значений по сформированному условию. Например, следующий запрос выбирает имя персоны по условию, зависящему
от типа сущности Person:
SELECT p.name CASE TYPE(p)
WHEN Student THEN ’kid’ WHEN Guardian THEN ’adult’ WHEN Staff THEN ’adult’
ELSE ’unknown’ END
FROM Person p
Пример запроса со множеством скидок для разных групп клиентов:
UPDATE Customer c SET c.discount = CASE c.level
WHEN ’Gold’ THEN 20
WHEN ’SILVER’ THEN 15
WHEN ’Bronze’ THEN 10 ELSE 5
END
Если целевой объект некоторого выражения не найден в хранилище, то он полагается равным NULL. Для условных выражений, содержащих NULL, язык запросов использует семантику SQL92:
•если сравнение или арифметическая операция имеет неизвестное значение,
она возвращает NULL;
•два значения NULL не равны друг другу. Сравнение двух значений NULL не определено;
•проверка IS NULL преобразует значение NULL в TRUE, а IS NOT NULL в FALSE;
•булевские операции и сравнения используют трехзначную логику со значе-
ниями TRUE, FALSE и UNKNOW (T, F, U). Для операндов T, F результаты совпадают с классической логикой;
•для операции AND, если один из операндов — U, результат будет U;
•для операции OR, если один из операндов не T, а второй — U, результат бу-
дет U;
•для операции NOT результат для операнда U есть U;
•для значения целого поля NULL возвращается объект класса Integer со значе-
нием NULL, а не базового типа int, в котором нет значения NULL.
13.8.6. Статья SELECT
Возвращаемый результат определяется выражением внутри статьи. Если ис-
пользуется несколько выражений, то результат запроса — массив Object[ ] с элементами, соответствующими порядку выражений в статье SELECT и их типами. В SELECT нельзязапрашиватьколлекции.Например,SELECT p.teams недопустимоевыражение,
так как teams — коллекция. Но можно запрашивать элемент коллекции, например:
SELECT t
FROM Player p, IN (p.teams) t
168
Следующий пример показывает запрос нескольких выражений:
SELECT c.name, c.country.name
FROM customer c
WHERE c.lastname = ’Coss’ AND c.firstname = ’Roxane’
Он возвращает список элементов Object[ ], где первый элемент — имя клиента, вто-
рой — название страны.
Агрегатные функции в операциях выбора
Результат запроса может быть вычислен как значение агрегатной функции, при-
ведённой в таблице 13.3.
|
|
Таблица 13.3 |
|
Агрегатные функции |
|
|
|
|
Имя |
Тип значения |
Описание |
AVG |
Double |
Среднее значение поля |
COUNT |
Long |
Количество результатов |
MAX |
Тип поля |
Максимальное значение поля |
MIN |
Тип поля |
Минимальное значение поля |
SUM |
Long (для целых), |
Сумма всех значений поля в |
|
Double (для дробных), |
наборе |
|
BigInteger. BigDecimal |
|
Если результирующий набор пуст, то для AVG, COUNT, MAX, MIN или SUM возвращается NULL, для COUNT — 0.
Примеры
Среднее значение поля quantity сущности Order:
SELECT AVG(o.quantity)
FROM Order o
Сумма значений поля price в пунктах lineItems заказа для сущности Order с име-
нем Roxane Coss:
SELECT SUM(l.price)
FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = ’Coss’ AND c.firstname = ’Roxane’
Число элементов в наборе Order:
SELECT COUNT(o)
FROM Order o
Число пунктов заказов, у которых есть стоимость, для клиента Hal Incandenza в наборе Order:
SELECT COUNT(l.price)
FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = ’Incandenza’ AND c.firstname = ’Hal’
Ключевое слово DISTINCT
Ключевое слово DISTINCT запрещает включение дубликатов значений в результат. Если запрос возвращает тип java.util.Collection, не допускающий дубликаты,
то можно использовать в операторе SELECT ключевое слово DISTINCT.
169
Выражения-конструкторы
Выражения-конструкторы создают новые экземпляры объектов, соответствую-
щие опции запроса WHERE. В приведённом ниже примере создаются экземпляры CustomerDetail для Customer. CustomerDetail хранит имя клиента и название страны
проживания. Запрос возвращает список List экземпляров CustomerDetail.
SELECT NEW com.xyz.CustomerDetail(c.name, c.country.name)
FROM customer c
WHERE c.lastname = ’Coss’ AND c.firstname = ’Roxane’
Опция ORDER BY
Опция позволяет упорядочить возвращаемый запросом набор значений или
объектов. Если опция содержит несколько элементов, то они образуют составной ключ
сортировки. Опция ASC определяет прямой (по умолчанию), а DESC — обратный по-
рядок сортировки. Нельзя сортировать запросы, не возвращающие наборы значений. Пример правильного запроса:
SELECT o
FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = ’CA’
ORDER BY o.quantity, o.totalcost
Пример неправильного запроса (в запросе нет значения quantity):
SELECT p.product_name
FROM Order o, IN(o.lineItems) l JOIN o.customer c WHERE c.lastname = ’Faehmel’ AND c.firstname = ’Robert’ ORDER BY o.quantity
Опция GROUP BY
Опция GROUP BY используется для группировки значений свойств набора. Следующий запрос группирует клиентов по стране и возвращает число клиентов в
странах:
SELECT c.country, COUNT(c)
FROM Customer c GROUP BY c.country
Опция HAVING
Опция HAVING используется совместно с GROUP BY для ограничений значе-
ний результата запроса. Следующий пример запроса группирует заказы по статусу их
клиентов и возвращает статус и среднее значение totalPrice для всех заказов, соответствующих статусу клиентов. При этом запрос рассматривает только клиентов со статусом 1, 2 или 3, поэтому другие клиенты не учитываются при подсчёте количества:
SELECT c.status, AVG(o.totalPrice) FROM Order o JOIN o.customer c
GROUP BY c.status HAVING c.status IN (1, 2, 3)
13.9. Примеры запросов
Java Persistence Query Language
В п. 1.4 данной работы был приведён пример приложения для работы с СУБД PostgreSQL, в котором использовалась техника запросов Criteria API, описанная ниже в главе 14. Изменения, которые необходимо проделать в тексте описания класса Org_ techFacade для использования запросов JPQL, приведены ниже. Для сравнения кода старый текст закомментирован, что позволяет оценить детали сходства и различия.
170
Файл Org_techFacade.java
Класс-посредник (фасад) для связывания бинов сущности и вида с хранили-
щем данных в БД: package EntityGGIS;
import dbGGIS.Org_tech; import java.util.List; import javax.ejb.Stateless;
import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query;
//import javax.persistence.criteria.CriteriaQuery; //import javax.persistence.criteria.Root;
/**
*
* @author cyx */ @Stateless
public class Org_techFacade { @PersistenceContext(unitName = "GGISCyxPU") private EntityManager em;
public void create(Org_tech org_Tech) { em.persist(org_Tech);
}
public void edit(Org_tech org_Tech) { em.merge(org_Tech);
}
public void remove(Org_tech org_Tech) { em.remove(em.merge(org_Tech));
}
public Org_tech find(Object id) { return em.find(Org_tech.class, id);
}
public List<Org_tech> findAll() {
//CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); //cq.select(cq.from(Org_tech.class));
//return em.createQuery(cq).getResultList(); return em.createQuery("SELECT ot FROM Org_tech ot")
//.setMaxResults(10)
.getResultList();
}
public List<Org_tech> findRange(int[] range) {
//CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); //cq.select(cq.from(Org_tech.class));
171
//Query q = em.createQuery(cq); //q.setMaxResults(range[1] - range[0]); //q.setFirstResult(range[0]);
//return q.getResultList();
Query q = em.createQuery("SELECT ot FROM Org_tech ot"); q.setMaxResults(range[1] - range[0]); q.setFirstResult(range[0]);
return q.getResultList();
}
public int count() {
//CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); //Root<Org_tech> rt = cq.from(Org_tech.class); //cq.select(em.getCriteriaBuilder().count(rt));
//Query q = em.createQuery(cq);
//return ((Long) q.getSingleResult()).intValue();
Query q = em.createQuery("SELECT count(ot) FROM Org_tech ot"); return ((Long) q.getSingleResult()).intValue();
}
}
Читателю предстоит сравнить обе техники доступа к базам данных и сделать выбор при разработке своих приложений. Но все-таки следует заметить следующее:
•язык JPQL более близок к стандарту языка SQL, принятому в реляционных
СУБД;
•тексты на языке JPQL более компактны и естественны;
•для использования JPQL необходимо знание языка SQL, в Criteria API сам за-
прос на языке SQL генерируется вызовом некоторых методов;
•функциональность обоих инструментов эквивалентна друг другу.
172