Шаг 25.
Использование OLE-документов в приложениях. Хранение OLE-объектов в базах данных. Использование памяти и методов-наследников класса TDataSet
На этом шаге мы рассмотрим еще один способ размещения в базе данных OLE-объекта.
Пример, приведенный на предыдущем шаге, имеет массу недостатков. Главным из них является тот факт,
что пользователь должен вручную инициировать загрузку содержимого BLOB-поля в компонент TOleContainег и сохранение
содержимого TOleContainer в таблице. Такое поведение приложения противоречит традиционному принципу создания пользовательских
интерфейсов для форм просмотра и редактирования данных, гласящему, что данные в интерфейсных элементах при перемещении по записям,
содержащимся в доставленном на рабочую станцию наборе данных, должны обновляться автоматически и сохраняться автоматически.
Если преодолеть первый недостаток данного приложения, добившись автоматического обновления данных в OLE-контейнере и сохранения
их в таблице, тут же проявится его второй недостаток, заключающийся в постоянном сохранении и загрузке данных с диска. Дисковые операции
вполне допустимы при ручных манипуляциях с OLE-коитейнером, но при автоматическом обновлении и сохранении они могут привести
к заметному снижению производительности приложения.
Реализуя принцип автоматического обновления и сохранения данных при выполнении навигационных методов компонентов TDataSet,
следует учитывать, что компонент TOleContainer не может быть связан с источником данных. Поэтому в простейшем случае необходимо
использовать методы BeforeScroll и AfterScroll компонента-наследника класса TDataSet. В обработчике события
BeforeScroll следует проверить, было ли изменено содержимое OLE-коитейпера. Это достигается путем проверки свойства
Modified компонента TOleContainer. Если в этом компоненте были произведены какие-либо изменения, то создается поток
данных в памяти, куда первоначально заносится некоторая последовательность байтов (назовем ее условно "цифровой подписью"; стоит, однако,
отдавать себе отчет в том, что к настоящей цифровой подписи эта последовательность байтов отношения не имеет). Подпись будет в дальнейшем
нужна при чтении данных: анализируя ее, можно определить, находятся ли данные для компонента TOleContainer в текущей записи.
Затем используется метод SaveToStream компонента TOleContainer:
const
Signature: Integer = -525465623;
. . . .
procedure TForm1.Table1BeforeScroll(DataSet: TDataSet);
var
Stream: TMemoryStream;
begin
if OleContainer1.Modified then
begin
Stream := nil;
try
Stream := TMemoryStream.Create;
Stream.Write(Signature,SizeOf(Signature));
if Assigned(OleContainer1.OleObjectInterface) then
OleContainer1.SaveToStream(Stream);
Stream.Seek(0, soFromBeginning);
try
Table1.Edit;
TBLOBField(Table1.FieldByName('Graphic')).
LoadFromStream(Stream);
Table1.Post;
OleContainer1.Modified := False;
except
Table1.Cancel;
end;
finally
if Assigned(Stream) then Stream.Free;
end;
end;
end;
procedure TForm1.Table1AfterScroll(DataSet: TDataSet);
var
Stream: TMemoryStream;
N: Integer;
begin
OleContainer1.DestroyObject;
Stream := nil;
try
Stream := TMemoryStream.Create;
TBLOBField(Table1.FieldByName('Graphic')).SaveToStream(Stream);
Stream.Seek(0, soFromBeginning);
if Stream.Size > 4 then
begin
Stream.Read(N, SizeOf(N));
if N = Signature then
OleContainer1.LoadFromStream(Stream);
end;
OleContainer1.Modified := False;
finally
if Assigned(Stream) then Stream.Free;
end;
end;
Текст этого приложения со всеми дополнительными файлами можно взять
здесь (257 Кб).
В заархивированной базе данных biolife.db содержимое поя Graphic у первых двух записей изменено.
На рисунке 1 приведено содержимое этого поля у второй записи.

Рис.1. Результат работы приложения
Прежде всего обработчик события AfterScroll очищает текущее содержимое OLE-контейнера. После этого создается поток
данных в памяти, куда и переносится содержимое BLOB-поля. Затем следует удостовериться, что поток данных содержит более 4 байт
информации (иначе в нем не поместится даже "цифровая подпись"). После этого производится чтение "цифровой подписи" и при ее совпадении
со значением константы Signature производится загрузка данных и установка свойства Modified равным False,
что позволяет корректно определить, были ли произведены изменения содержимого OLE-контейнера после загрузки данных.
На следующем шаге мы рассмотрим создание OLE-контейнера в виде VCL-компонента.
Предыдущий шаг
Содержание
Следующий шаг