CategoriesDataSet позволяет автоматически подтверждать сделанные изменения, если задать свойство AutoCommit в True. Теперь после вызова метода Post компонент CategoriesDataSet будет автоматически вызывать CategonesTransaction CommitRetainmg, сохраняя сделанные пользователем изменения и не закрывая при этом сам запрос. Такой подход уже снижает вероятность Deadlock, который возможен при наличии длинных незакрытых транзакций, в контекст которых производились изменения данных.
Тем не менее, FIBPlus предлагает другую возможность, которая сводит вероятность возникновения Deadlock практически к нулю. TpFIBDataSet может работать одновременно в контексте двух транзакций. Одна длинная транзакция, в контексте которой данные только читаются, и другая короткая транзакция, в контексте которой выполняются все модифицирующие запросы.
Переименуем CategoriesTransaction в CategoriesReadTransaction и добавим еще один компонент CategoriesWriteTransaction. После этого зададим свойство UpdateTransaction у CategoriesDataSet в CategoriesWriteTransaction. Таким образом, теперь CategoriesDataSet подключен сразу к двум компонентам TpFTBTransaction (рис. 2.26).
Рис 2.26. Разделение читающей и пишущей транзакций
После вызова метода Post компонент CategoriesDataSet будет вызывать метод Commit у компонента CategoriesWriteTransaction. Однако, учитывая, что данные читаются в контексте совсем другой транзакции (CategoriesReadTransaction), это не вызовет закрытия всего CategoriesDataSet. To есть, используя FIBPlus, мы имеем настоящий режим AutoCommit, который уменьшает вероятность Deadlock и не мешает "видеть" нам актуальные значения всех записей. При использовании BDE в режиме AutoCommit вы не могли бы узнать реальные значения записей, пока не переоткроете запрос.
Кроме того, как уже упоминалось, для InterBase до версии 6.5 слишком частый вызов CommitRetaining мог привести к значительному "захвату" ресурсов сервером. При использовании механизма разделенных транзакций вы можете использовать режим AutoCommit без потерь производительности сервера для любых версий InterBase.
Механизм master-detail. Специальные опции TpFIBDatabase и TpFIBDataSet
Мы имеем возможность редактировать данные о категориях товаров и можем переходить к вопросам, связанным с построением связки master-detail. Для этого мы положим на форму дополнительные компоненты:
GoodsSource: TDataSource;
GoodsGrid: TDBGrid;
GoodsDataSet: TpFIBDataSet;
GoodsReadTransaction: TpFIBTransaction;
GoodsWriteTransaction: TpFIBTransaction;
AddGoodsButton: TButton;
EditGoodsButton: TButton;
DeleteGoodsButton: TButton;
"Свяжем" их так же, как и предыдущую группу компонентов, и напишем SelectSQL для GoodsDataSet:
SELECT * FROM "Goods"
WHERE "IdCategory" = :"Id"
Очевидно, что мы хотим выбрать при помощи detail-запроса только те товары, которые относятся к текущей категории. Значение параметра : "Id" должно браться из поля "Id" таблицы "Categories". Чтобы это происходило автоматически, необходимо задать свойство GoodsDataSet.DataSource равным CategoriesSource. Теперь сгенерируем модифицирующие запросы для GoodsDataSet так же, как мы делали это раньше для CategoriesDataSet.
После автоматической генерации мы должны внести некоторые изменения в полученные запросы. Рассмотрим, в частности, запрос для InsertSQL:
INSERT INTO "Goods"(
"Id",
"Name",
"Price",
"IdCategory" )
VALUES(
:"Id",
:"Name",
:"Price",
:"IdCategory"
)
Очевидно, что при добавлении нового товара, мы должны задать параметр : "IdCategory" текущим значением поля "Id" из таблицы "Categories". FIBPlus позволяет делать это автоматически при помощи префикса "MAS_", о котором мы уже упоминали выше:
INSERT INTO "Goods"(
"Id" ,
"Name",
"Price",
"IdCategory" )
VALUES(
:"Id",
:"Name",
:"Price",
:"MAS_Id"
)
Теперь мы указали явным образом, что значение для поля "Goods"."IdCategory" нужно брать из поля "Id" таблицы "Categories", которая является master- таблицей для таблицы "Goods". To же изменение необходимо внести в запрос UpdateSQL
UPDATE "Goods" SET
"Id" = :"Id",
"Name" = :"Name",
"Price" = :"Price",
"IdCategory" = :"MAS_Id"
WHERE
"Id" = 'OLD_Id"
Теперь изменим немного код в процедуре FormCreate:
procedure TMainForm.FormCreate(Sender: TObject);
begin
with TimFile. Create (' ib_price. mi ') do begin
pFIBDatabasel.DBName := ReadStringt'Options', 'DBPath',
'C:\IBPRICE.GDB');
Free;
end;
pFIBDatabasel.Open;
CategoriesDataSet.Open;
GoodsDataSet.Open;
end;
He забудем заполнить свойства AutoUpdateOptions, чтобы GoodsDataSet автоматически генерировал значения первичного ключа (рис 2 27)
Можно запустить приложение Двигаясь вверх и вниз по CategoriesGrid, вы можете наблюдать, как автоматически изменяется содержимое в GoodsGrid Связка master-detail уже работает.