Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование от Чертенка.ру Выпуск 10. Работа с Oracle в Delphi. Компонент TOraQuery.


Информационный Канал Subscribe.Ru

Доброго времени суток, уважаемые подписчики!

Сегодня будет продолжен рассказ о компоненте TOraQuery.

В прошлом выпуске мы научились выполнять любые запросы. В большинстве случаев нужно будет выбирать информацию, отвечающую каким либо условиям. Для примера, можно выбрать только людей, фамилия которых начинается на А:
select fam, name, otch, birthday from clientphis where fam like 'А*'
Если нужно найти людей с фамилией, начинающейся на Г, то можно конечно написать такой запрос
select fam, name, otch, birthday from clientphis where fam like 'Г*'
Как наверное заметили, у нас получилось два одинаковых запроса, которые отличаются только условием отбора записей. А ведь таких условий в процессе работы программы может генерироваться несколько сотен и для Оракла это будут уникальные запросы, что отрицательно скажется на производительности и масштабируемости всей системы.

В этой ситуации на помощь приходят параметрические запросы. Выше указанные запросы можно преобразовать в параметрический так:
select fam, name, otch, birthday from clientphis where fam like :fam
Обратите внимание на выражение ":fam" - эта конструкция определяет параметр с именем fam. Имя параметру можно давать любое, а не только по имени поля, но в определенных ситуациях действуют некоторые правила задания имен параметров. К рассмотрению этих правил мы вернемся в будущем.

Перед выполнением такого запроса нужно обязательно установить значения параметров. Для этого можно использовать или коллекцию Params, которая содержит список всех параметров запроса (нумерация начинается с 0) или метод ParamByName, который работает с указанным по имени параметром.

Модифицируем последний наш пример так, чтобы выбирать людей с фамилией, начинающейся на введенные нами символы.
1. Изменим запрос у OraQuery1 на select fam, name, otch, birthday from clientphis where upper(fam) like upper(:fam)
2. Перепишем обработчик OnClick кнопки:

procedure TForm1.Button1Click(Sender: TObject);
begin
  //закрываем датасет
  OraQuery1.Close;
  //устанавливаем значение параметра
  OraQuery1.ParamByName('fam').AsString := Edit1.Text + '*';
  //или установить значение параметра можно так:
  //OraQuery1.Params[0].AsString := Edit1.Text + '*';
  //выполняем запрос
  OraQuery1.Execute;
end;
Как видите, нет ничего сложного. Удобство параметров особенно проявляется тогда, когда нужно работать с датами, так как при этом не нужно приводить дату к формату, принимаемому сервером.

Если Вы дочитали до этих строк, то наверное подумали, что параметры можно использовать не только для задания значений выражений, но и также для определения полей и таблиц, например, было бы неплохо выполнить такой запрос:
select * from :table - для выборки данных из любой таблицы
или
select * from table order by :ordfield - для задания сортировки по любому полю.

К сожалению, непосредственно такие запросы ни один сервер не может выполнить и сразу будет выдавать ошибку. Можно конечно динамически формировать запрос, но ODAC имеет более красивое решение, а именно макросы. Использовать макросы также легко, как и параметры. Для задания макроса используется символ & (а не :) и для работы с макросами есть метод MacroByName/Macros (сравните с ParamByName/Params).

Рассмотрим работу с макросами на конкретном примере:

  OraQuery1.Close;
  OraQuery1.SQL.Text := 'select fam, name, otch, birthday from
  clientphis order by @sort'
  OraQuery1.MacroByName('sort').Value := Edit1.Text;
  OraQuery1.Execute;
Теперь в строке редактирования можно указать имя поля, по которому будет идти сортировка.

Также макросы можно использовать для динамического задания условий и т.д. без непосредственного формирования нужного sql-кода, например:
MyQuery.SQL.Text := 'SELECT * FROM Dept WHERE DeptNo > 20 &Cond1';
MyQuery.Macros[0].Value := 'and DName is NULL';
MyQuery.Execute;
в этом случае на сервер уйдет следующий запрос:
SELECT * FROM Dept WHERE DeptNo > 20 and DName is NULL

Как могли заметить, с помощью параметров такой запрос нельзя сконструировать. Но что делать, если нужно периодически отключать условие 'and DName is NULL'? Можно конечно макросу присвоить пустую строку, но ODAC содержит более красивое и элегантное решение - достаточно у макроса сбросить свойство Active (по умолчанию оно установлено):
MyQuery.Macros[0].Active:= False;
в этом случае на сервер уйдет запрос SELECT * FROM Dept WHERE DeptNo > 20

В использовании макросов и параметров нет ничего заумного, так что смело берите эти возможности на вооружение. И не забывайте, что Оракл очень любить параметрические запросы.

Настало время про связь master/detail. Что это за связь я рассказsвать не буду, так как это выходит за рамки статьи. Просто расcкажу, какими способами в ODAC'е ее можно организовать.

Если обратили внимание на словосочетание какими способами, то уже догадались, что ODAC поддерживает несколько способов организации связи master/detail. Рассмотрим их более подробно (на примере демонстрационной базы, которая ставится вместе с Ораклом).

Обычно связь master/detail организуется для таблиц, которые связаны на уровне СУБД отношением foreign key/primary key. Для организации связи master/detail нам понадобятся два компонента TOraQuery и один компонент TDataSource (TOraDataSource):

var
  Master, Detail: TOraQuery;
  MasterSource: TDataSource;
begin
  // Создаем master датасет
  // Можно также воспользоваться компонентом на форме
  // Как Вы помните по предыдущим выпускам, ODAC автоматически
  // подключает компоненты к OraSession.
  Master := TOraQuery.Create(Self);
  Master.SQL.Text := 'SELECT * FROM Department';

  // Создаем detail датасет
  // Обратите внимание что для detail датасета мы указываем
  // параметрический запрос
  Detail := TOraQuery.Create(Self);
  Detail.SQL.Text := 'SELECT * FROM Employee WHERE DepNo = :DepNo';

  // Связываем Detail с Master с помошью MasterSource
  MasterSource := TDataSource.Create(Self);
  MasterSource.DataSet := Master;
  // именно здесь и устанавливается связь
  Detail.MasterSource := MasterSource;

  // Сначала открываем основной запрос
  // и только потом - дочерний
  Master.Open;
  Detail.Open;
end;
Примечание. С помощью дизайнера форм можно создать связь master/detail не написав ни одной строчки кода (!!!), нужно всего лишь "бросить" на форму соответствующие компоненты и настроить нужные свойства. В худшем случае нужно в коде открыть в правильном порядке эти датасеты.

Несколько важных пояснений. Имя параметра в дочернем запросе (detail датасет) должно соответствовать имени поля в основном запросе. Значение для параметра второго запроса автоматически берется из поля основного запроса. При скроллинге основного датасета, дочерний запрос автоматически будет выполнятся с нужным параметром, поэтому если дочерний запрос будет "тяжелым", то будет наблюдаться некотороя "заторможенность" интерфейса. При добавлении новой записи в дочернию таблицу (запрос) в поле с foreign key автоматически вставляется значение primary key из текущей записи основной таблицы (запроса).

ODAC поддерживает еще один способ организации master/detail с использованием свойств MasterFields/DetailsFields:

var
  Master, Detail: TOraQuery;
  MasterSource: TDataSource;
begin
  // Создаем master датасет
  Master := TOraQuery.Create(Self);
  Master.SQL.Text := 'SELECT * FROM Department';

  // Создаем detail датасет
  // Сравните запрос с первым способом
  Detail := TOraQuery.Create(Self);
  Detail.SQL.Text := 'SELECT * FROM Employee';

  // Устанавливаем связь
  Detail.MasterFields := 'DepNo';   // primary key в основной таблице Department
  Detail.DetailFields := 'DepNo';   // foreign key в дочерней таблице Employee

  // Указываем основоную таблицу
  MasterSource := TDataSource.Create(Self);
  MasterSource.DataSet := Master;
  Detail.MasterSource := MasterSource;

  // Сначала открываем основной запрос
  // и только потом - дочерний
  Master.Open;
  Detail.Open;
end;
Во втором случае имена полей, по которым устанавливается связь, указываются не в дочернем запросе, а в специальных свойствах. Если Вы внимательно читали предыдущий выпуск, то могли бы подумать что дочерний запрос будет возвращать все записи, а не только те, что нам нужны. Однако это не так. Во время выполнения программы ODAC самостоятельно изменит запрос на SELECT * FROM Employee WHERE DepNo = :DepNo и будет работать как в первом случае.

Какой вариант организации связи master/detail использовать - решать Вам. Я в силу привычки использую первый способ. В следующем выпуске я продолжу рассказ про OraQuery.

Ждем Ваших откликов на емайл 5781-author@subscribe.ru или subscr@chertenok.ru


Приглашаем авторов в рассылку!


С уважением,
координатор рассылки Алексей aka Gelios.

Наши координаты:

сайт - www.delphi.chertenok.ru
форум - www.forum.chertenok.ru
контактный email - 5781-author@subscribe.ru

Другие проекты:

www.travel.chertenok.ru - сайт о путешествиях!



Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.allofdelphi
Архив рассылки
Отписаться Вебом Почтой
Вспомнить пароль

В избранное