Приветствую Вас Гость | RSS

Меню сайта

Реклама

Категории раздела
ADO [17]
ASCII и CSV [12]
Access [20]
Alias [24]
BDE [37]
BLOB поля [19]
Clipper [2]
DB2 [2]
DBASE и DBF [26]
Fox Pro [1]
Interbase [21]
MSSQL [0]
ODBC [10]
Oracle [0]
Paradox [0]
SQL [29]
Sybase [1]
База данных [0]
Закладки [2]
Записи [0]
Индексы [10]
Компоненты и Базы данных [0]
Модуль данных [3]
Отчеты [2]
Ошибки БД [17]
Поиск [16]
Поля [0]
Сортировка и Фильтр [6]
Таблицы [0]

Наш опрос
Какие компоненты добавлять больше?
Всего ответов: 48

Статистика

Онлайн всего: 3
Гостей: 3
Пользователей: 0

Форма входа

Главная » Статьи » Базы данных » BDE

Использование буфера записей BDE
Все идет к тому, что BDE в ближайшее время окончательно сдаст позиции компонентам прямого доступа к данным (IBX, dbExpress). 
Но все наработанное с использованием BDE сразу не перепишешь и не выбросишь. Компоненты прямого доступа существенно расширяют возможности разработчика. 
Недавно понадобилось напрямую работать с буфером записей запроса (TQuery), если бы можно было использовать IBQuery проблем бы с этим не возникло, но буфер записей BDE закрыт и просто до него не достучаться.
Задача стояла следующая: в БД (Interbase) при работе с достаточно большой таблицей появилась необходимость при навигации в ReadOnly DBGrid и нажатию короткой клавиши отмечать записи для отложенной печати (поле SOST := 1). 
Данная задача решается несколькими способами:

Перевести Query в режим редактирования установить поле в необходимое значение и вызвать метод Query.Post; 
C использованием другого Query выполнить Update записи, затем переоткрыть Query. 
C использованием другого Query выполнить Update записи, затем в буфере записей выставить значение нужного поля. 
Первый метод не подходит по понятным соображениям, к тому же в нашем случае Query не редактируемый (RequestLive = false). 
Второй слишком долгий и ведет к увеличению сетевого трафика.
Третий метод возможно реализовать только с использованием IBX или ClientDataSet, что в этом конкретном случае не приемлемо. 
Поэтому для решения задачи третьим методом пришлось искать где BDE хранит полученные от IB сервера данные, вот что из этого получилось: 
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Db, DBTables, Grids, DBGrids, BDE, Menus;

type
  TForm1 = class(TForm)
  DataSource: TDataSource;
  Query: TQuery;
  DBGrid: TDBGrid;
  Database: TDatabase;
  SetFldQ: TQuery;
  PopupMenu: TPopupMenu;
  Sost1: TMenuItem;
  Sost0: TMenuItem;
  procedure FormCreate(Sender: TObject);
  procedure Sost1Click(Sender: TObject);
  procedure Sost0Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  procedure SetSost(AValue: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function GetBDERecBuff(ACursor: TQuery): Pointer; {cursor}
var
  P, P1: Pointer;
  CurNo, RecNo, RecSize: Integer;
begin
  //Вызов этого метода синхронизирует положение курсора
  //DataSet и BDE
  ACursor.UpdateCursorPos;

  P := ACursor.Handle;
  Inc(PChar(P), $1E);
  P := Pointer(P^);
  Inc(PChar(P), $7E);
  P := Pointer(P^);
  Inc(PChar(P), $14);
  P := Pointer(P^);
  Inc(PChar(P), $36);
  P := Pointer(P^);

  // Получаем внутренний BDE-шный номер текущей записи
  P1 := P;
  Inc(PChar(P1), $A);
  Inc(PChar(P1), $2);
  RecNo := Integer(P1^) - 1;

  Inc(PChar(P), $4);
  P := Pointer(P^);

  // Получаем внутренний BDE-шный номер курсора
  P1 := P;
  Inc(PChar(P1), $11F);
  P1 := Pointer(P1^);
  CurNo := Word(P1^);

  // Получаем размер записи
  P1 := P;
  Inc(PChar(P1), $113);
  RecSize := Word(P1^);

  // Получаем указатель на массив где хранятся указатели на
  // буфера всех BDE курсоров
  Inc(PChar(P), $4);
  P := Pointer(P^);
  Inc(PChar(P), $68);
  P := Pointer(P^);

  // Выбираем из массива нужный нам указатель
  Inc(PChar(P), 4 * (CurNo - 1));
  P := Pointer(P^);

  // Получаем указатель на текущую запись
  Inc(PChar(P), RecNo * RecSize);

  Result := P;
end;

procedure PutFldToBDEBuf(ACursor: TQuery; AField: TField; pValue: Pointer);
var
  P: Pointer;
begin
  // Получаем указатель на текущую запись
  P := GetBDERecBuff(ACursor);
  //складываем нужное значение в буфер BDE
  Check(DbiPutField(ACursor.Handle, AField.FieldNo, P, pValue));
  //Вызов Resync для пересчета Calc-полей и немедленного отображений изменении на
  экране
  ACursor.Resync([]);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Database.Open;
  Query.DataBaseName := Database.DatabaseName;
  SetFldQ.DataBaseName := Database.DatabaseName;
  DBGrid.PopupMenu := PopupMenu;
  Sost1.ShortCut := TextToShortCut('Ctrl+A');
  Sost0.ShortCut := TextToShortCut('Ctrl+S');
  Query.SQL.Text := 'SELECT * FROM AKODIF ORDER BY CODE';
  Query.Open;
  SetFldQ.SQL.Text := 'UPDATE AKODIF SET SOST = :SOST WHERE CODE = :CODE';
  SetFldQ.Prepare;
end;

procedure TForm1.SetSost(AValue: Integer);
begin
  SetFldQ.ParamByName('SOST').AsInteger := AValue;
  SetFldQ.ParamByName('CODE').AsInteger := Query.FieldByName('CODE').AsInteger;
  SetFldQ.ExecSQL;
  PutFldToBDEBuf(Query, Query.FieldByName('SOST'), @AValue);
end;

procedure TForm1.Sost1Click(Sender: TObject);
begin
  SetSost(1);
end;

procedure TForm1.Sost0Click(Sender: TObject);
begin
  SetSost(0);
end;

end.
Все описанное выше работает в Delphi 3, Delphi 4, Delphi 5. С BDE 5.01, idapi32.dll от 12.11.1999 размер 589 312. С другими версиями BDE скорее всего работать не будет! 

Все, вышеописанное есть некий частный результат и автор желал бы получить отклик от тех, кого интересует эта тема.
Категория: BDE | Добавил: Skinner (05.07.2008) | Автор: Александр Шпихернюк E
Просмотров: 387 | Рейтинг: 0.0/0
  Delphi Lab   Главная   Регистрация   Вход  
Интересная Цитата

Поиск

Магазин


Copyright MyCorp © 2025 Хостинг от uCoz