Выбрать главу

SELECT * FROM "Categories"

Теперь изменим немного код в процедуре:

procedure TMainForm.FormCreate(Sender: TObject);

begin

with TiniFile.Create('ib_price.ini') do begin

pFIBDatabasel.DBName := ReadString('Options', 'DBPath',

'C:\IBPRICE.GDB');

Free ;

end;

pFIBDatabasel.Open;

CategoriesDataSet.Open;

end;

В свойстве DataSet у компонента CategoriesSource (TDataSource) мы укажем CategoriesDataSet, а в свойстве DataSource у компонента CategoriesGrid (TDBGrid) укажем CategoriesSource. Теперь все данные, полученные в результате запроса, будут отображены в CategoriesGrid. Нам не нужно явным образом запускать транзакцию перед открытием запроса, поскольку по умолчанию свойство CategoriesDataSet.Options содержит ключ poStartTransaction и компонент сам запускает транзакцию После запуска приложения и открытия базы данных мы увидим следующий результат (рис. 2.20):

Рис 2.20. Вид запущенного приложения

Вместо CategoriesGrid мы могли использовать любой визуальный db-компонент, который используется в связке с TDataSource. Это мог быть TDBEdit, TDBLabel, TDBMemo и т. д., а также любые сторонние компоненты, которые придерживаются данного стандарта (TDBGridEh, например).

Как сделать запрос редактируемым? Автоматическая генерация модифицирующих запросов в design-time и run-time

Если вы попробуете исправить какие-то значения в CategoriesGrid, то увидите, что в текущем состоянии мы имеем iead-only-запрос Для того чтобы наш запрос стал редактируемым, или "живым", нам надо написать несколько дополнительных запросов, которые будут автоматически выполнятся компонентом CategonesDataSet при редактировании данных в CategoriesGrid. Необходимо заполнить свойства (рис. 2.21).

Рис 2.21. Свойства CategonesDataSet с запросами для чтения и модификации данных

FIBPlus включает специальный design-time-редактор для редактирования и генерации модифицирующих запросов. Вы можете вызвать "Generator SQLs" из контекстного меню, если нажмете правой кнопкой мыши на компоненте CategonesDataSet (рис. 2.22)

Для генерации модифицирующих запросов необходимо сначала указать основную таблицу в списке Если в запросе участвует только одна таблица, то она будет выбрана в списке автоматически После этого необходимо нажать кнопку Get Table Fields для заполнения списков "Key Fields" и "Update Fields '. В первом списке нужно выделить те поля, которые будут вставлены в условие WHERE во всех модифицирующих запросах. В списке "Update Fields" необходимо выделить те поля, которые мы хотим редактировать. По умолчанию выделены все поля таблицы "Categories" Теперь достаточно нажать кнопку Generate SQLs и получить автоматически все модифицирующие запросы, которые вы можете увидеть на закладке SQLs Например, мы получим следующий запрос для свойства InsertSQL

INSERT INTO "Categories"(

"Id" ,

" Name" ,

"GoodsCount"

)

VALUES(

:"Id",

:"Name",

:"GoodsCount"

)

Puc 2.22. Редактор компонента TpFIBDataSet, предназначенный для генерации модифицирующих запросов

Обратите внимание также на запрос для свойства RefreshSQL:

select * from "Categories"

WHERE

(

"Categories"."Id" = :"OLD_Id"

)

Это такой же выбирающий запрос, как и запрос в свойстве SelectSQL, но возвращать он должен только одну запись - текущую Теперь, после создания всех запросов, когда пользователь будет редактировать запись в CategoriesGrid, CategonesDataSet автоматически заполнит значения параметров : "Id", . "Name" и т д., теми значениями полей, которые наберет пользователь. После выполнения метода Post (который, в частности, вызывается при нажатии клавиши Enter в CategonesGnd) CategoriesDataSet выполнит соответствующий модифицирующий запрос После редактирования записи будет выполнен запрос из свойства UpdateSQL, при вставке новой записи - из InsertSQL, а при удалении записи - из DeleteSQL После выполнения любого модифицирующего запроса (кроме удаления) CategoriesDataSet автоматически выполняет запрос из RefreshSQL, подставляя в качестве условия текущие значения параметров. Это позволяет "узнать" значения всех полей текущей записи, если они были изменены при помощи триггеров базы данных.

Несколько слов о специальных префиксах для параметров, которые используются в FIBPlus.

Префикс "OLD_" фактически означает текущее значение одноименного поля или же предыдущее значение поля Термин "предыдущее значение" имеет смысл в запросе на удаление. Во всех остальных случаях, когда нужны актуальные значения полей, можно обходиться без данного префикса.

Префикс "NEW_" означает новое значение поля и фактически имеет смысл только в запросах на изменение и вставку. Однако новые значения полей в этих ситуациях также являются и текущими, а значит, префикс "NEW_" можно опускать

Существует также специальный префикс "MAS_", но мы доберемся до него несколько позже.

Поскольку мы сгенерировали все необходимые модифицирующие запросы, то уже можем запустить наше приложение, добавить пару категорий, изменить их названия и даже целиком удалить их.

Тем не менее генерация модифицирующих запросов в design-time не всегда удобна FIBPIus позволяет разработчику автоматически генерировать нужные запросы во время работы приложения, основываясь на запросе из свойства SelectSQL Для этого нужно использовать свойство AutoUpdateOptions (рис 223).

Рис 2.23. Комплексное свойство AutoUpdateOptions

Необходимо "включить" ключ "AutoReWriteSqls", указать ключевое поле, которое будет использовано в условиях WHERE (в нашем случае, это поле "Id") и указать название модифицируемой таблицы ("Categories"), поскольку в реальности запросы могут быть многотабличными. Теперь свойства InsertSQL, DeleteSQL, UpdateSQL и RefreshSQL будут генерироваться автоматически при открытии CategonesDataSet. To есть фактически мы имеем генератор запросов в run-time, что бывает очень удобно.

Есть еще один момент, связанный с генерацией модифицирующих запросов Например, если мы редактируем только название категории, то после нажатия на Entei на сервер будет отправлен запрос, в котором изменены два поля и Name и GoodsCount Фактически же мы изменяли только одно поле - "Name".В итоге если запись таблицы содержит значительный объем данных (например, длинные строковые поля), то при малейшем исправлении даже одного поля на сервер будут "уходить" все данные. При многопользовательской работе это создаст дополнительный лишний трафик Данной ситуации можно избежать но для этого необходимо, чтобы приложение выполняло 6oлee эффективные изменяющие запросы, например запрос:

UPDATE "Categories" SET

"Name" = ."Name"

WHERE

"Id" = :"OLD_Id"

в котором, как вы видите, участвует только то поле, значение которого действительно было изменено. Такая возможность существует, если мы включим ключ UpdateOnlyModifiedFields (разумеется, этот ключ действует, только если мы используем режим генерации запросов в run-time). В случае редактирования только поля "Name" компонент CategoriesDataSet автоматически сгенерирует запрос, приведенный выше, и будет генерировать каждый раз новые запросы в зависимости от того, какие поля изменялись.

Поскольку теперь наш CategoriesDataSet стал модифицируемым, то мы можем написать обработчики событий OnClick у трех кнопок справа от CategoriesGrid:

procedure TMainForm AddCatButtonClick(Sender TObject);