Прежде всего, разрешите поздравить Вас с наступившим Новым годом и
Рождеством! Хотелось бы выразить Вам признательность за Ваши отзывы,
они очень ценны для нас. Будем надеяться, что и в новом году Вы будете оставаться с
нами. В этом выпуске я продолжу рассказ про ODAC. Сегодня будет
подробно рассмотрен основной компонент TOraQuery.
В 7
выпуске
я рассказал о том, как подключится к серверу Oracle, теперь пришло
время научиться выбирать данные.
Основным компонентом для выборки данных является TOraQuery,
который может выполнить любую команду Оракла.
Этот компонент имеет много
свойств и методов, часть из них наследуется от TDataset, а остальные
специфичны только для ODAC (в других библиотеках их может и не быть).
Рассмотрение всех методов/свойств выходит за рамки данного цикла, но
об основных свойствах и методах я расскажу.
Первое, на что хочется обратить внимание, это свойство AutoCommit
(обратите внимание, что такое же свойство есть и у TOraSession). Если
это свойство установлено у TOraQuery и у TOraSession, то при
выполнении команд DML insert/update/delete commit будет выполнен
автоматически. Для небольших проектов это может быть полезным, но для
серьезных проектов нужно ручное управление транзакциями, поэтому это
свойство нужно отключить.
Свойства FetchAll и FetchRows отвечают за то, сколько записей
результата запроса компонент будет получать от сервера. Если FetchAll
= True, то с сервера будут считаны все записи результата выполнения
запроса (представьте, что запрос возвращает скажем 500 тыс записей,
сколько времени уйдет на пересылку данных по сети такого объема
информации?). Для справочников и небольших выборок это свойство можно
установить в True, а вот для больших выборок рекомендуется оставить
его по умолчанию.
Если FetchAll = False, то с сервера будет считываться FetchRows за
раз. Если пользователю не нужны все данные запроса, то в этом режиме
будет идти огромная экономия траффика, а также улучшится реакция
приложения на действия пользователя. Если приложению понадобятся еще
данные, то автоматически с сервера будет скачана новая порция данных.
Следует учесть, что RecordCount вернет не кол-во строк в
результирующем наборе (оно будет известно только тогда, когда все
данные будут прочитаны с сервера), а количество строк, которые были
реально загружены с сервера - это число будет кратно FetchRows. Если
же нужно знать сколько записей вернет запрос, то нужно установить флаг
Options.QueryRecCount. При этом TOraQuery на основании исходного
запроса сам сгенерирует запрос вида select count(*) from () и это число будет возвращать RecordCount. Тут следует учесть
один важный момент - время выполнения запроса может быть увеличено в
два раза, так как в действительности будут выполняться два запроса, а
не один. Для Оракла есть еще один путь, чтобы узнать, сколько записей
вернет запрос. Для этого запрос нужно переписать в виде select t.*,
count(*) over() as cnt from table t. При этом в результирующем запросе
будет добавлен новый столбец cnt, содержащий во всех записях
количество строк, которые вернет запрос.
Примечание. Конструкция
count(*) over() называется аналитической функцией и, насколько мне
известно, аналитические функции присутствуют только в Оракле (хотя я
могу и ошибаться). Если Вас заинтересовали аналитические функции в
Оракле, то пишите мне, в одном из следующих выпусков могу опубликовать
статью по аналитическим функциям.
Следующие свойства, на которые хотелось бы обратить внимание - это
SQL, SQLInsert, SQLDelete, SQLLock, SQLRefresh, SQLUpdate.
В SQL задается любая команда Оракла (ну кроме наверное create/drop
database :)).
В SQLInsert задается sql-команда по вставке записи insert. Если здесь
указана команда, то OraQuery сможет выполнить такие методы, как
OraQuery.Insert/OraQuery.Append. В противном случае через датасет нельзя будет
вставить запись.
В SQLDelete задается sql-команда по удалению записи delete. Если здесь
задана команда, то именно она будет выполнена при удалении записи
через OraQuery.Delete. В противном случае через датасет нельзя будет
удалить запись.
В SQLLock задается sql-команда по блокировке одной записи. Блокировка
нужна для того, чтобы запретить нескольким транзакциям редактировать
одну и ту же запись. Указанная команда будет выполнена при вызове
метода OraQuery.Lock.
В SQLRefresh задается sql-команда по обновлению данных для текущей записи.
Команда будет выполнена при вызове метода OraQuery.RefreshRecord.
В SQLUpdate задается sql-команда по обновлению записи update. Если здесь
задана команда, то она будет выполнена при редактировании записи
через OraQuery.Edit.
Эти свойства мы еще рассмотрим более подбробно
ниже.
Хватит разглагольствовать, пора заняться практикой :)
Для
отображения результатов, нам понадобится еще компонент TDBGrid и
компонент TDataSource (TOraDataSource). Компонент TDataSource является
связующим звеном между OraDataset и DBGrid.
Итак, приступим. Создаем новый проект, настраиваем компонент
TOraSession (см
7 выпуск).
Кладем на форму компонент TOraQuery. Обратите внимание, что свойство
Session было автоматически установлено на наш компонент OraSession1.
Эта особенность играет важную роль при создании автономных отчетов в
FastReport. Добавляем на форму DBGrid и OraDataSource.
У компонента OraDataSource свойство Dataset установим в OraQuery1, а
свойство DataSource у DBGrid - в OraDataSource. На этом
подготовительные действия закончены.
Теперь введем какой нибудь запрос, например select fam, name, otch,
birthday from clientphis. Запрос можно ввести несколькими
способами:
1. Вызвать редактор свойсва SQL.
2. Дважды кликнуть на
OraQuery или в контекстном меню выбрать OraQuery Editor...
3.
В контекстном меню выбрать Designer...
4. В контекстном меню выбрать
Builder...
Примечание. Вы наверное заметили, что при
установке ODAC предлагал скачать бесплатные утилиты? 3 и 4 пункты как раз и реализуют
эти утилитки, но они не обязательны... Я предпочитаю использовать
второй способ.
Текст запроса ввели, осталось его выполнить. Для этого установим
свойство Active у OraSession и сразу же можем в гриде видеть результат
выполнения (если конечно ввели корректный запрос):
Поиграйтесь с гридом и обратите внимание, как ведет себя скроллбар
у грида и сравните его поведение с BDE. А ответ прост, грид для
позиционирования использует количество записей RecordCount, и как я
уже писал, ODAC наиболее корректно среди других библиотек вычисляет
это количество записей. ADO пытается выбрать все данные, а если их
несколько сотен тысяч или миллионов записей, то на это уйдет некоторое
время и приложение не будет реагировать на запросы пользователя и ОС,
но при этом скроллбар будет вести себя привычным образом. BDE читает
данные с сервера порциями, но размер порций контролируется на уровне
алиаса и будет действовать для всех компонент TOraQuery. При этом
скроллбар грида ведет себя некорректно.
Во время выполнения программы запрос можно выполнить тремя путями:
- Рассмотренным выше способом OraQuery.Active=True;
- OraQuery.Open; (эквивалентен первому способу)
- Универсальный для ODAC методом OraQuery.Execute. (Почему он
универсальный будет рассказано в следующем выпуске)
Расширим пример, чтобы можно было выполнять любой введенный запрос.
Для этого добавим компонент TEdit, куда будем вводить текст запроса и
TButton, в обработчике OnClick которого напишем следующий код:
procedure TForm1.Button1Click(Sender: TObject);
begin
OraQuery1.Close; -- закрываем датасет
OraQuery1.SQL.Text := Edit1.Text; -- устанавливаем текст запроса
OraQuery1.Execute; -- выполняем запрос
end;
В следующем выпуске я продолжу рассказ про OraQuery, в котором расскажу
про параметры, макросы, организацию связи master/detail, использование
объектов полей.