Обратите внимание, что в этой процедуре мы используем параметр bmRead при создании потока S. Очевидно, что для сохранения содержимого BLOB-поля в файл нам не нужно изменять само поле, поэтому мы создаем поток только для чтения. Еще более простым способом мы можем очистить содержимое BLOB-поля:
procedure TMainForm.ButtonlClick(Sender: TObject);
begin
pFIBDataSetl .Edit;
pFIBDataSetl.FieldByName('GRAPHIC').Clear;
pFIBDataSetl.Post;
end;
В этом случае даже не требуется создавать какие-либо потоки. Иногда также нужно знать, является ли BLOB-поле пустым или нет. При использовании визуальных компонентов типа TDBImage мы не можем быть в этом уверены. Согласитесь, что никто не мешает нам "нарисовать" пустую картинку и сохранить ее в BLOB-поле В этом случае мы не сможем отличить "на глаз": есть ли какое-то изображение в BLOB-поле или нет. Однако мы можем написать обработчик события OnDataChange компонента DataSourcel: TDataSource:
procedure TMainForm.DataSourcelDataChange(Sender: TObject;
Field: TField) ;
begin
CheckBoxl.Checked :=
pFIBDataSetl.FieldByName('GRAPHIC').IsNull;
end;
Это событие вызывается, в частности, при навигации по DBGridl; таким образом, мы всегда можем узнать, является ли текущее поле пустым или нет.
Если вы используете TpFIBQuery для работы с BLOB-полями, то общий принцип остается тем же - необходимо использовать потоки, однако, в отличие от TpFIBDataSet, вам не потребуется создавать какие-то специальные потоки. Например, мы можем написать следующую процедуру, которая сохранит в файлы все изображения из нашей таблицы:
pFIBQuery.SQL: SELECT * FROM BIOLIFE
procedure TMainForm.Button2Click(Sender: TObject);
var SaveFile: TFileStream;
Index: Integer;
begin
with pFIBQueryl do begin ExecQuery;
Index := 1;
while not Eof do begin
SaveFile := TFileStream.Create(IntToStr(Index) + '.bmp',
fmCreate);
FN('GRAPHIC').SaveToStream(SaveFile);
Next;
inc(Index);
SaveFile.Free;
end;
Close;
end;
end;
Метод FN является аналогом FieldByName.
Смысл кода, приведенного выше, совершенно очевиден: мы получаем все записи из таблицы BIOLIFE, в цикле получаем от сервера очередную запись из запроса, создаем файл при помощи потока SaveFile, сохраняем в него значение поля GRAPHIC и запрашиваем следующую запись при помощи метода Next. Аналогичным образом мы могли бы присваивать значение BLOB-параметру: pFIBQuery.SQL: INSERT INTO BIOLIFE (GRAPHIC) VALUES (7GRAPHIC)
procedure TMainForm.Button2Click(Sender: TObject);
var SaveFile: TFileStream;
Index: Integer;
begin
with pFIBQueryl do begin
Prepare;
for Index := 1 to 3 do begin
SaveFile := TFileStream.Create(IntToStr(Index) + '.bmp', fmOpenRead);
Params[0].LoadFromStream(SaveFile);
SaveFile.Free;
ExecQuery;
end;
Transaction.Commit;
end;
end;
Данный пример вставляет три новые записи в таблицу BIOLIFE и сохраняет в них изображения из некоторых файлов "l.bmp", "2.bmp" и "3.bmp".
Поскольку в данном примере для сохранения изменений использовался метод Commit, то необходимо перезапустить приложение, чтобы увидеть вставленные записи в DBGridl.
Локальная сортировка и локальная фильтрация
TpFIBDataSet позволяет разработчику оптимизировать работу с базой данных, используя в случае необходимости локальную сортировку данных и локальную фильтрацию. Термин "локальный" в данном случае означает, что в этих механизмах не используются дополнительные запросы к серверу. Таким образом, в определенных случаях вы можете значительно снизить сетевой трафик вашего приложения, а также увеличить скорость поиска или сортировки данных.
Локальная сортировка
Рассмотрим локальную сортировку на примере Sorting, который входит в поставку FIBPlus.
Как и все остальные примеры, приложение Sorting вы можете наши на сайте http://www.fibplus.net
Пример использует таблицу EMPLOYEE из базы данных Employee.gdb (рис. 2.67)
Рис 2.67. Внешний вид формы приложения, демонстрирующего локальную сортировку в TpFIBDataSet
MainDS.SelectSQL: SELECT * FROM EMPLOYEE
Все записи, полученные от сервера в результате запроса, сохраняются в локальном буфере компонента TpFIBDataSet.
Это одна из причин, из-за которой не рекомендуется использовать TpFIBDataSet для слишком больших выборок, - вам просто может не хватить оперативной памяти и работа приложения замедлится.
Предположим, что пользователь хочет отсортировать записи по полю FIRST_NAME. Очевидно, что мы можем сформировать новый запрос:
SELECT * FROM EMPLOYEE
ORDER BY FIRST_NAME
Чтобы получить новый порядок записей, необходимо переоткрыть наш запрос. Это работает, но означает, что мы будем повторно получать от сервера все •записи, несмотря на то что нам нужно было всего лишь поменять их визуальный порядок. Если предполагать, что нашим приложением могут пользоваться одновременно несколько пользователей, то затраты на подобные "сортировки" могут оказаться довольно значительными. Тем не менее выход существует, поскольку TpFIBDataSet позволяет сортировать данные внутри своего локального буфера, т. е. без необходимости получения всех записей заново.