Подобные "технологические" решения можно придумывать очень долго: поскольку фантазия разработчиков практически неистощима, мы можем найти выход из любой ситуации и обойти любое ограничение существующей технологии. Однако в данном случае решения "проблемы" проистекают от простого непонимания принципов работы IBDataSet. Поверьте, все гораздо проще.
В самом начале главы сказано, что TIBDataSet порожден классом TDataSet, а значит, наследует основные принципы его работы. У TIBDataSet как наследника TDataSet существует три основных метода для изменения данных: Delete, Insert (Append) и Edit.
Предположим, что мы хотим вставить новую запись в наш IBDataSetl по нажатии кнопки:
procedure TForml.ButtonlClick(Sender: TObject);
begin
with IBDataSetl do begin
Insert;
FieldByName('EMP_NO').Aslnteger := 147;
FieldByName('DEPT_NO').Aslnteger := 600;
FieldByName('JOB_CODE').AsString := 'VP';
FieldByName('JOB_GRADE') .Aslnteger : = 2 ;
FieldByName('SALARY').Aslnteger := 105900;
FieldByName('HIRE_DATE').AsDateTime := Now;
FieldByName('JOB_COUNTRY').AsString := 'USA';
FieldByName('FIRST_NAME').AsString := 'Иван';
FieldByName('LAST_NAME').AsString := 'Иванов';
Post;
end;
end;
Теперь поясним, как это работает. После того как мы вызываем метод Insert, IBDataSetl формирует пустой буфер для нашей (пока еще не введенной) записи. Далее мы задаем значения нужных полей при помощи вызовов метода FieldByName и заканчиваем (точнее, подтверждаем) редактирование вызовом метода Post. В этот момент IBDataSetl выполняет запрос, прописанный в свойстве InsertSQL, подставив вместо параметров те значения полей, которые мы задали.
Если запрос выполнился успешно, то IBDataSetl автоматически выполняет RefreshSQL для обновления только что вставленной записи - для проверки изменений, внесенных на стороне базы данных.
Аналогичным образом мы можем редактировать записи. Например, мы можем модифицировать все записи в нашем запросе:
procedure TForml.ButtonlClick(Sender: TObject);
begin
with IBDataSetl do begin
First;
while not Eof do begin
Edit;
FieldByName('LAST_NAME').AsString :=
trim(FieldByName('LAST_NAME').AsString) + ', esquire;
Post;
Next ;
end;
end;
end;
Принцип тот же самый, что и при вставке записей. Мы вызываем метод Edit, подготавливая буфер текущей записи для редактирования, потом меняем значения поля при помощи FieldByName, а потом заканчиваем редактирование, вызвав метод Post. В результате IBDataSetl подставляет значения полей записи в ModifySQL и выполняет запрос.
Оговоримся, что в реальной практике подобная обработка большого множества записей не является хорошим решением. Гораздо легче было бы выполнить одну команду UPDATE, которая добавила бы строку ', esquire' ко всем записям таблицы. Пример выше дан только для демонстрации метода Edit.
Как видно из примеров выше, нет никакой нужды ни в каких дополнительных компонентах, синхронизации о прочих непонятных "телодвижениях", если мы хотим редактировать данные в IBDataSet программно.
И снова про транзакции
Новичков иногда пугает "особенность" IBX закрывать все запросы при подтверждении или "откате" транзакции. Разместим на нашей форме две кнопки, как показано на рис. 2.10: Button 1 (свойство Caption равно Commit) и Button2 (Rollback).
Рис 2.10. Кнопки управления транзакцией
Далее напишем следующие обработчики событий нажатия на эти кнопки:
procedure TForml.ButtonlClick(Sender: TObject);
begin
IBTransactionl.Commit;
end;
procedure TForml.Button2Click(Sender: TObject);
begin
IBTransactionl.Rollback;
end;
Теперь если мы запустим приложение и нажмем любую из этих кнопок, то увидим, что после завершения транзакции наш запрос также будет закрыт.
Это действие совершенно очевидно, поскольку, как уже было сказано, любой запрос должен выполнятся только в рамках определенной транзакции и, таким образом, если транзакция уже закрыта, то запрос не может быть активным.
Однако для тех разработчиков, которые до сих пор пользовались BDE, такое поведение компонентов непривычно. Существует два метода. Первый: запоминать активные записи во всех открытых запросах перед закрытием транзакции, потом заново открывать все запросы и перемещать указатели текущих записей на "старое место". Именно так и работает механизм неявного переоткрытия, реализованный в BDE. Второй - это использовать методы CommitRetaining и RollbackRetaining, впервые появившиеся в InterBase 5.x. Эти методы в целом аналогичны методам Commit и Rollback, однако они реализованы таким образом, что сервер автоматически перезапускает транзакцию и не закрывает открытых запросов. Использование CommitRetaining и RollbackRetaining позволит вам избегать массовых операций переоткрытия ваших запросов.
Однако тут есть одна особенность, которая сразу не бросается в глаза. Предположим, что вы делали какие-то изменения, после чего решили отменить их и вызвали RollbackRetaining. Все модифицирующие запросы, которые были отправлены на сервер в контексте данной транзакции, будут отменены, однако локальный буфер TIBDataSet останется неизмененным.