Шаг 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-компонента.




Предыдущий шаг Содержание Следующий шаг