Delphi-Help

  • Increase font size
  • Default font size
  • Decrease font size
Главная

FIBPlus: Работа с внутренним кэшем

Оцените материал
(2 голосов)

FIBPlus: Работа с внутренним кэшем

Когда вы выполняете запрос SELECT с использованием компонента TpFIBDataSet, то данные, полученные из базы данных на сервере (набор данных), помещаются на компьютер клиента в так называемый внутренний кэш — область оперативной памяти, или внутренний буфер. Вся работа с набором данных на клиентской стороне осуществляется с этим внутренним кэшем. В дальнейшем изменения данных в кэше могут помещаться в базу данных на сервере, а могут и оставаться только в кэше.

Перед началом статьи, для тех кому нужен выделенный сервер, предлагаю купить дедик.

Если отключен режим «отложенных» изменений (в компоненте TpFIBDataSet свойство CachedUpdates установлено в False), то все изменения данных в кэше (добавление — Insert, удаление — Delete и изменение — Edit) сразу будут сохраняться в базе данных.

Тем не менее, существует также множество методов компонента TpFIBDataSet, позволяющих изменять данные непосредственно в памяти TpFIBDataSet. Такие изменения не будут отражаться в базе данных. Это методы: CacheOpen, CacheDelete, CacheAppend, CacheEdit, CacheInsert, CacheModify, CacheRefresh, и CacheRefreshByArrMap.

Одни методы позволяют задавать любой источник ввода данных для добавления или изменения записи, другие позволяют получать данные только из другого набора данных.

Замечание. Помните, что при работе только с внутренним кэшем не будут выполняться никакие проверки условий, заданных для базы данных (NOT NULL, CHECK CONSTRAINT и др.), не будут вызываться никакие триггеры. В частности, вы можете помещать в кэш любое количество записей, имеющих одинаковое значение первичного (PRIMARY) или уникального (UNIQUE) ключа, внешний ключ (FOREIGN KEY) может ссылаться на несуществующие родительские ключи и т.д. Также в этом случае не будут вызываться обработчики событий базы данных для компонента TpFIBDataSet, кроме обработчиков событий AfterClose, AfterOpen, BeforeClose, BeforeOpen, DatabaseDisconnecting, DatabaseDisconnected, а также AfterScroll и BeforeScroll.

Для иллюстрации использования методов работы с внутренним кэшем возьмем базу данных FIBSAMPLE.GDB, используемую в большинстве примеров по FIBPlus.

Создайте в Delphi или C++Builder новый проект InternalCache. Положите на форму следующие компоненты:

pFIBDatabase1: TpFIBDatabase;
pFIBTransaction1: TpFIBTransaction;
pFIBDataSet1: TpFIBDataSet;
pFIBDataSet2: TpFIBDataSet;
DataSource1: TDataSource;
DataSource2: TDataSource;
DBGrid1: TDBGrid;
DBGrid2: TDBGrid;
InsertOne: TButton;
InsertAll: TButton;
DeleteOne: TButton;
DeleteAll: TButton;

[Image]

Рисунок. Проект InternalCache. Работа с внутренним кэшем

Свойство DBName компонента pFIBDatabase1 ссылается на базу данных FIBSAMPLE.GDB. Компоненты pFIBDataSet1 и pFIBDataSet2 используют таблицу PERSON. Оператор в свойстве SelectSQL обоих компонентов pFIBDataSet:

SELECT CODPERS,
       FIRST_NAME,
       LAST_NAME,
       COUNTRY
FROM PERSON
ORDER BY CODCTR, CODREG

Компонент pFIBDataSet1 будет читать данные из таблицы PERSON и помещать их в сетку DBGrid1 (находится в левой части формы), а компонент pFIBDataSet2 мы используем для работы с внутренним кэшем. Для отображения содержимого его набора данных используется компонент DBGrid2 в правой части формы. Компоненты DataSource используются для связи DBGrid с соответствующими наборами данных.

У компонента pFIBDataSet2 другие операторы SQL кроме SelectSQL нам не потребуются. Более того, поскольку этот компонент не будет вносить изменения в базу данных, можно не указывать для него транзакций, то есть можно оставить пустыми значения его свойств Transaction и UpdateTransaction.

Открытие и закрытие набора данных

Метод CacheOpen позволяет открыть пустой набор данных. До выполнения этого метода необходимо соединиться с базой данных. CacheOpen выполняет метод Prepare для оператора SELECT, хранящегося в свойстве SelectSQL. Это единственное обращение к базе данных при использовании Cache методов, поскольку TpFIBDataSet все-таки должен сформировать правильные внутренние структуры для описания полей. Открытие набора данных естественным образом выполняется в обработчике события формы OnShow.

pFIBDataSet1.CacheOpen;

Получить пустой набор данных также можно, задав в свойстве SelectSQL оператор SELECT, возвращающий пустой набор данных. Более того, вы можете открыть обычным образом набор данных, который будет содержать какое-то количество записей, и использовать методы Cache для изменения, удаления или добавления записей. Никакие изменения внутреннего кэша при использовании методов Cache не приведут к изменению данных в базе данных.

Для проверки, каким методом был открыт набор данных, можно использовать свойство CachedActive компонента TpFIBDataSet. Если его значение True, то набор данных был открыт методом CacheOpen.

По завершении всех работ с внутренним кэшем с целью освобождения системных ресурсов следует закрыть набор данных обычным способом: методом Close или присваиванием свойству Active компонента TpFIBDataSet значения False.

Замечание для любителей редактировать данные в DBGrid. Если вы открыли набор данных методом CacheOpen, то редактирование и добавление данных в сетке будет невозможным. Не следует также допускать редактирование данных в сетке для набора данных, открытого обычным образом, если для этого набора данных будут использованы методы Cache, поскольку такое редактирование может привести к непредсказуемым результатам.

Добавление записей в набор данных

Для добавления новых записей в кэш можно использовать несколько методов.

Методы CacheAppend и CacheInsert

Рассмотрим вначале два метода: CacheAppend и CacheInsert. CacheAppend добавляет новую запись в конец набора данных, CacheInsert вставляет запись после текущей записи. Однако, это верно, если в наборе данных в свойстве Options под-свойство poKeepSorting установлено в False. Если же это свойство имеет значение True, и оператор SELECT содержит фразу ORDER BY (как в нашем случае), то оба метода будут работать одинаково, вставляя запись в набор данных в соответствии со значениями ключей сортировки.

Метод CacheAppend существует в двух вариантах:

procedure CacheAppend(aFields: array of integer;
   Values: array of Variant); overload;

Аналогичные варианты у метода CacheInsert:

procedure CacheInsert(aFields: array of integer;
  Values: array of Variant); overload;

Первый вариант методов позволяет сформировать новую запись, задав значения любых полей записи. Методам передается список номеров полей и список их значений. Напишите обработчик события щелчка по кнопке InsertOne (на которой обозначено “>”).

procedure TFormMain.InsertOneClick(Sender: TObject);
begin
  if not (pFIBDataSet1.IsEmpty) then
  begin
    pFIBDataSet2.CacheAppend([0, 1, 2, 3],
      [pFIBDataSet1.FieldByName('CODCTR').AsString,
       pFIBDataSet1.FieldByName('CODREG').AsString,
       pFIBDataSet1.FieldByName('CENTER').AsString,
       pFIBDataSet1.FieldByName('REGNAME').AsString]
      );          
    pFIBDataSet1.CacheDelete;
  end;
end;

Здесь методу CacheAppend передается список номеров всех четырех полей (нумерация начинается с нуля) и список значений этих полей, которые выбираются из текущей записи набора данных pFIBDataSet1. Если в Delphi всё можно выполнить в одной операции, то в C++Builder вначале нужно объявить два массива (int и Variant) по четыре элемента в каждом, а затем методу CacheAppend передавать имена этих массивов и количество элементов массивов минус единица:

pFIBDataSet2->CacheAppend(aFields, 3, Values, 3);

После создания новой записи в наборе данных pFIBDataSet2 из набора данных pFIBDataSet1 удаляется текущая запись с использованием метода CacheDelete.

Напоминаем, что удаление записи из кэша первого набора данных не приводит к удалению этой записи из базы данных.

Запустив программу на выполнение, можно увидеть, как при щелчке по кнопке текущая запись переносится из левой сетки в правую.

Использование метода CacheInsert в первом варианте осуществляется точно таким же образом путем замены CacheAppend на CacheInsert.

Методы CacheAppend и CacheInsert позволяют выбирать значения полей из любого источника данных. Для простоты мы использовали данные текущей записи набора данных pFIBDataSet1.

Второй вариант методов CacheAppend и CacheInsert позволяет добавить запись в кэш, задав значение только первого поля. Перепишите обработчик щелчка по кнопке следующим образом:

procedure TFormMain.InsertOneClick(Sender: TObject);
begin
  if not (pFIBDataSet1.IsEmpty) then
  begin
    pFIBDataSet2.CacheAppend(
      pFIBDataSet1.FieldByName('CODCTR').AsString, True);          
    pFIBDataSet1.CacheDelete;
  end;
end;

Точно так же используется и второй вариант метода CacheInsert (с точностью до обозначения имени метода).

Методы Modify и Refresh

Существует другая группа методов, позволяющих добавлять новые записи во внутренний кэш: CacheModify, CacheRefresh и CacheRefreshByArrMap.

Метод CacheModify

Метод CacheModify позволяет как изменять текущую запись, так и добавлять новые записи. Его прототип:

Delphi

procedure CacheModify(aFields: array of integer; Values:
  array of Variant; KindModify: byte);

Методу также передается список номеров полей, список значений и признак KindModify, который может иметь значения:

0 — изменить запись,

1 — вставить запись,

2 — добавить запись.

Напишите следующий обработчик щелчка по кнопке InsertAll (на которой обозначено “>>”). В обработчике этого события мы собираемся переместить все записи из первого набора данных во второй.

procedure TFormMain.InsertAllClick(Sender: TObject);
begin
  if not (pFIBDataSet1.IsEmpty) then
  begin
    pFIBDataSet1.First;
    while not pFIBDataSet1.Eof do
    begin
      pFIBDataSet2.CacheModify([0,1,2,3],
       [pFIBDataSet1.FieldByName('CODCTR').AsString,
       pFIBDataSet1.FieldByName('CODREG').AsString,
       pFIBDataSet1.FieldByName('CENTER').AsString,
       pFIBDataSet1.FieldByName('REGNAME').AsString], 1);
      pFIBDataSet1.CacheDelete;
    end;
  end;
end;

Здесь просматриваются все записи первого набора данных, и каждая перемещается во второй набор данных.

Использование метода CacheModify похоже на использование методов CacheAppend и CacheInsert. Здесь также передается список номеров полей и список значений, при этом добавляется еще один параметр (1), указывающий, что требуется вставить запись. Если нужно добавлять запись в конец набора данных, то значение этого параметра нужно заменить на 2.

Обратите внимание, что хотя мы и добавляли во второй набор данных записи из другого набора данных, тем не менее, все предыдущие методы позволяют вводить любые данные, поступающие из любого источника.

Метод CacheRefresh

Следующий метод CacheRefresh позволяет изменять или добавлять данные только из набора данных. Его прототип:

procedure CacheRefresh(FromDataSet: TDataSet;
  Kind: TCachRefreshKind; FieldMap: TStrings);

· Параметры метода.
FromDataSet задает набор данных — источник данных.
Kind — вид операции:
frkEdit — изменение записи,
frkInsert — добавление записи.
FieldMap содержит список имен полей, добавляемых в запись или изменяемых в записи.

Для иллюстрации использования этого метода напишите в несколько упрощенном виде обработчик события щелчка по кнопке DeleteOne (с заголовком ”<”):

procedure TFormMain.DeleteOneClick(Sender: TObject);
var
  StringList: TStrings;
begin
  if not (pFIBDataSet2.IsEmpty) then
  begin
    StringList := TStringList.Create;
    StringList.Add('CODCTR');
    StringList.Add('CODREG');
    StringList.Add('CENTER');
    StringList.Add('REGNAME');
    pFIBDataSet1.CacheRefresh(pFIBDataSet2, frkInsert, StringList);
    pFIBDataSet2.CacheDelete;
    StringList.Free;
  end;
end;

Этот обработчик переносит текущую запись из второго набора данных в первый и удаляет запись из второго набора данных. Обратите внимание, что мы создавали переменную абстрактного класса TStrings, но инициализировали ее классом TStringList, поскольку объект абстрактного класса создавать не рекомендуется.

Метод CacheRefreshByArrMap

Следующий метод CacheRefreshByArrMap также позволяет изменять или добавлять данные только из набора данных. Его прототип:

procedure CacheRefreshByArrMap(
      FromDataSet: TDataSet; Kind: TCachRefreshKind;
      const SourceFields, DestFields: array of String);

Для иллюстрации использования этого метода напишите обработчик события щелчка по кнопке DeleteAll (с заголовком ”<<”):

procedure TFormMain.DeleteAllClick(Sender: TObject);
begin
  if not (pFIBDataSet2.IsEmpty) then
  begin
    pFIBDataSet2.First;
    while not pFIBDataSet2.Eof do
    begin
      pFIBDataSet1.CacheRefreshByArrMap(
        pFIBDataSet2, frkInsert,
        ['CODCTR', 'CODREG', 'CENTER', 'REGNAME'],
        ['CODCTR', 'CODREG', 'CENTER', 'REGNAME']);
      pFIBDataSet2.CacheDelete;
    end;
  end;
end;

Изменение записей во внутреннем кэше

Для изменения данных внутреннего кэша можно использовать методы: CacheEdit, CacheModify, CacheRefresh и CacheRefreshByArrMap.

Мы рассмотрели методы CacheModify, CacheRefresh и CacheRefreshByArrMap. Методы позволяют изменять любые поля в текущей записи набора данных на основании значения полей другого набора данных (источника данных). Приведем пример использования этих методов для изменения значений нескольких полей текущей записи. Напоминаем, что эти изменения не попадут в базу данных.

procedure TFormMain.BModifyClick(Sender: TObject);
begin
  if not (pFIBDataSet1.IsEmpty)
     and not (pFIBDataSet2.IsEmpty) then
    pFIBDataSet2.CacheModify([2,3],
     [pFIBDataSet1.FieldByName('CENTER').AsString,
     pFIBDataSet1.FieldByName('REGNAME').AsString], 0);
end;
 
procedure TFormMain.BModRefreshClick(Sender: TObject);
var
  StringList: TStrings;
begin
  if not (pFIBDataSet1.IsEmpty)
     and not (pFIBDataSet2.IsEmpty) then
  begin
    StringList := TStringList.Create;
    StringList.Add('CENTER');
    StringList.Add('REGNAME');
    pFIBDataSet2.CacheRefresh(pFIBDataSet1, frkEdit, StringList);
    StringList.Free;
  end;
end;
 
procedure TFormMain.BRefreshByArrMapClick(Sender: TObject);
begin
  if not (pFIBDataSet1.IsEmpty)
     and not (pFIBDataSet2.IsEmpty) then
  begin
    pFIBDataSet2.CacheRefreshByArrMap(
      pFIBDataSet1, frkEdit,
      ['CENTER', 'REGNAME'],
      ['CENTER', 'REGNAME']);
  end;
end;

Все эти процедуры выполняют одно и то же действие — изменяют значения двух последних полей (CENTER и REGNAME) в текущей записи набора данных pFIBDataSet2.

Метод CacheEdit имеет следующий прототип:

procedure CacheEdit(aFields: array of integer; Values: array of Variant);

Методу передается список номеров изменяемых полей и список новых значений этих полей. Для C++Builder необходимо также указывать и размер списка минус единица.

Примеры использования метода CacheEdit:

if not (pFIBDataSet1.IsEmpty) then
  pFIBDataSet1.CacheEdit([0], [’RUS’];

В этих примерах заменяется значение первого поля текущей записи набора данных pFIBDataSet1 на RUS.

Удаление записей из внутреннего кэша

Удаление текущей записи выполняется при помощи метода CacheDelete, например:

if not (pFIBDataSet1.IsEmpty) then
  pFIBDataSet1.CacheDelete;

Заключение

Задачей данной статьи было пояснить способы использования методов работы с внутренним кэшем. Реальный контекст, в котором они могут пригодиться, зависит от вас. В большинстве случаев они могут пригодиться для создания удобного пользовательского интерфейса работы с данными. В частности, пример двунаправленного списка на основе обычных компонентов TpFIBDataSet, неплохо демонстрирует такие возможности.

Прочитано 11617 раз

Авторизация



Счетчики