Object-relational mapping класс для работы с базой данных – TCommonListEngine

Продолжение статьи Object-relational mapping класс для работы с базой данных – общие сведения. Подробно рассматривается базовый для всех остальных классов TCommonObject , который реализует основные общие методы и свойства объектов.

Как уже было сказано TCommonListEngine наследуется от TCommonObject и реализует общие методы для реализации доступа к списку записей из базы данных. В нем перегружаются виртуальные методы базового класса TCommonObject и добавляются новые методы и свойства необходимые для базового класса доступа к списку записей из базы данных. По сравнению с родительским классом добавлены следующие методы и свойства:

 

FItems: TList;

function AddItem: Pointer;virtual;

destructor Destroy;virtual;

function GetAll: Boolean; virtual;

function SetKeyValues(AFields: TFields; AItem: Pointer): Boolean;virtual;

procedure ClearItems;

function FindByID(AID , ASID: Integer): TCommonEngine;

function DeleteItem(AIndex: Integer): Boolean;

property OnFillParams: TFillParamsProc;

property ExternalParams: Pointer;

property SelectAllString: string;

 

Подробнее об этих свойствах виртуальных и перегруженных методах:

 

FItems: ( TList ) – список ссылок на экземпляры единичных записей из таблицы БД, создается и удаляется при в месте с экземпляром класса.

 

function AddItem: Pointer; virtual; – Добавляет в список элемент новый, в наследуемо классе перегружается и в список добавляется элемент соответствующего типа.

 

constructor Create; override; – Конструктор в нем заполняется SelectAllString – запрос, который отбирает идентификаторы для списка объектов из таблицы. Необходимо заполняется значение процедурного свойства OnFillParams, которое вызывается в момент заполнения параметров запроса к БД. Это позволит при необходимости изменить параметры отбора путем замены процедуры, которая их заполняет.

Обязательно прописываем  inherited Create;

 

destructor Destroy; virtual; – В деструкторе освобождается память всех элементов списка.

Обязательно прописываем inherited

 

function Save(ASaveItems: Boolean = True): Boolean; override; – Сохраняет все элементы списка, вызывая для каждого из них метод  Save. В наследуемом классе имеет смысл заполнить

Result:= inherited Save( ASaveItems );

 

function Refresh: Boolean; override; – Обновляет данные по элементам списка, вызывая для каждого из них методы GetByID; GetAdditionalInfo;

 

function FindByID(AID , ASID: Integer): TCommonEngine; – Осуществляет поиск элемента списка по ключевым значениям, если ключевое поле только одно – id, то ASID = – 1;

 

function Delete: Boolean; override; – Удаляет все элемент списка путем заполнения свойства isDeleted:= true и последующим сохранением элемента. Имеет смысл заполнить в наследуемом классе

Result:= inherited Delete;

 

function DeleteItem(AIndex: Integer): Boolean; – Удаляет элемент списка по его индексу. Имеет смысл заполнить в наследуемом классе

Result:= inherited DeleteItem(AIndex);

 

function GetByID: Boolean;override; – Выполняет SQL – запрос для выбора идентификаторов при отборе элементов в список, при этом вызывается процедура GetAll, которая и реализует отбор ключевых значений для всего списка (создана для совместимости с родительским объектом).

 

function GetAdditionalInfo: Boolean; override; – Функция заполняет поля дополнительной информации списка.

 

function GetAll: Boolean; virtual; – Отбирает все элементы списка из базы данных. При этом ключевые поля отбираются запросом из свойства SelectAllString, и заполнения параметров запроса функцией из процедурного свойства OnFillParams, после чего для каждой отобранной записи добавляется новый элемент списка вызовом функции AddItem и заполнение ключевых полей для нового элемента вызовом функции SetKeyValues. После чего для каждого элемента списка вызывается функция Refresh, при помощи вызова функции Refresh всего списка.

 

function SetKeyValues(AFields: TFields; AItem: Pointer): Boolean;virtual; – Устанавливает ключевые значения для выбранного элемента списка, при выполнении процедуры GetAll.

 

procedure ClearItems;  – Освобождает память для всех элементов списка и очищает сам список.

 

Свойство OnFillParams: TFillParamsProc; – Процедурное свойство, которое вызывается при заполнении параметров запроса. При необходимости подменяется другой процедурой, а строка SelectAllString для того что бы можно было варьировать запрос для отбора элементов в список, инициализируются в конструкторе. Для работы списка хотя бы с одним списком значений необходимо описать в классе процедуру

procedure FillParams(AParams: TParameters; AParamValues: Pointer)

, в которой будет явно прописано извлечение параметров из указателя AParamValues и присвоение х соответствующим параметрам AParams запроса выбора списка записей;

 

procedure TTempList.FillParams(AParams: TParameters; AParamValues: Pointer);

var

lKeyValues: PKeyValues;

begin

lKeyValues:= AParamValues;

with AParams do

begin

ParamByName('lKeyValues1').DataType:= ftInteger;

ParamByName('lKeyValues1').Value:= lKeyValues^.ID;

 

ParamByName('lKeyValues2').DataType:= ftInteger;

ParamByName('lKeyValues2').Value:= lKeyValues^.SID;

end;

end;

Свойство ExternalParams: Pointer; – Ссылка на значения параметров используемых при заполнении параметров SQL – запроса, необходимо создавать либо структуру либо класс, записывать в указатель ссылку на него, при заполнении параметров извлекать из указателя значения, и при завершении работы класса освобождать ресурсы.

 

Свойство SelectAllString: string; – строка, которая содержит запрос для отбора идентификаторов для списка элементов, заполняется в конструкторе.

 

Таким образом, для реализации наследника от TCommonEngine необходимо перегрузить в наследуемом классе следующие функции и добавить функцию procedure FillParams(AParams: TParameters; AParamValues: Pointer)

 

{—-  Base function ——————————————————}

function AddItem: Pointer; override;//*

destructor Destroy; override;

function GetAll: Boolean; override;

function SetKeyValues(AFields: TFields; AItem: Pointer): Boolean; override; //*

{—-  Additional function ————————————————}

procedure FillParams(AParams: TParameters; AParamValues: Pointer)//*

{—-  Fields ————————————————————-}

{—-  Additional Fields ————————————————–}

 

Функции, отмеченные звездочкой, обязательно перегружать, и дополнять своим кодом.
Небольшой пример реализации данного класса.

procedure TTempList.FillParams(AParams: TParameters; AParamValues: Pointer);
var
  lKeyValues: PKeyValues;
begin
  lKeyValues:= AParamValues;
  with AParams do
  begin
    ParamByName('lKeyValues1').DataType:= ftInteger;
    ParamByName('lKeyValues1').Value:= lKeyValues^.ID;

    ParamByName('lKeyValues2').DataType:= ftInteger;
    ParamByName('lKeyValues2').Value:= lKeyValues^.SID;
  end;
end;

function TTempList.SetKeyValues(AFields: TFields;
  AItem: Pointer): Boolean;
var
  lTemp: TTemp;
begin
  Result:= inherited SetKeyValues(AFields,AItem);
  lTemp:= TTemp(AItem);
  with AFields do
  begin
    lTemp.SID:= FieldByName('KeyValue2').AsInteger;
  end;
end;

function TTempList.AddItem: Pointer;
var
  lTemp: TTemp;
begin
  inherited AddItem;
  lTemp:= TTemp.Create;
  FItems.Add(lTemp);
  lTemp.Fconnection:= FConnection;
  Result:= Pointer(lTemp);
end;

Код который реализует данный класс. Скачать его можно здесь uCommonEngine.

TCommonListEngine = class(TCommonObject)
  private
    FOnFillParams: TFillParamsProc;
    FExternalParams: Pointer;
    FSelectAllString: string;
    procedure SetExternalParams(const Value: Pointer);
    procedure SetOnFillParams(const Value: TFillParamsProc);
    procedure SetSelectAllString(const Value: string);
    //function GetSelectedFields(AQuery: TADOQuery): Boolean;
  public
      {список записей из таблицы БД.}
    FItems: TList;
      {Добавляет в список элемент новый, в наследуемо классе перегружается и в
      список добавляется элемент соответствующего типа}
    function AddItem: Pointer;virtual;
      {Коструктор в нем заполняется
      SelectAllString - запрос, который отбирает идентификаторы для списка
      объектов из таблицы.

      Необходимо заполняется значение процедурного свойства OnFillParams, которое
      вызывается в момент запленеия параметров запроса к БД. Это позволит при
      необходимоссти измениьт параметры отбора путем замены процедуры, которая
      их заполняет

      обязательно прописываем  inherited Create
      }
    constructor Create;override;
      {В деструкторе освобождается память всех элементов списка.
      Обязательно прописываем  inherited 
      }
    destructor Destroy;virtual;
      {Сохраняет все элементы списка, вызывая для каждого из них метод  Save,
      обязательно дописываем inherited Save}
    function Save(ASaveItems: Boolean = True): Boolean;override;
      {Обновляет данные по элементам списка вызывая для каждого из них медоты
        GetByID;
        GetAdditionalInfo;
      }
    function Refresh: Boolean;override;
      {Осуществляет поиск элемента списка по ключевым значениям, если ключеапое
       поле только одно - id, то ASID = - 1 }
    function FindByID(AID , ASID: Integer): TCommonEngine;
      {Удаляет все эелемент списка путем заполнения свойства isDeleted:= true и
      последующим сохранением элемента. Имеет смысл заполнить в наследуемом
      классе
        Result:= inherited Delete;
      }
    function Delete: Boolean; override;
      {Удаляет элемент списка по его индексу
        имеет смысл заполнить в наследуемом классе
        Result:= inherited DeleteItem(AIndex);
      }
    function DeleteItem(AIndex: Integer): Boolean;
      {Выполняет SQL - запрос для выбора идентификаторов при отборе элементов в
      список, при этом вызывается процедура GetAll, которая и реализует отбор
      ключевых значений для всего списка (создана для совместимости с
      родительским объектом.
      }
    function GetByID: Boolean;override;
      {Функция заполняет поля дополнительной информации для списка}
    function GetAdditionalInfo: Boolean; override;
      {Отбирает все элементы списка из базы данных}
    function GetAll: Boolean; virtual;
      {Устанавливает ключевые значения дл выбранного элемента списка}
    function SetKeyValues(AFields: TFields; AItem: Pointer): Boolean;virtual;
      {Освобождает память для всех элементов списка}
    procedure ClearItems;
      {процедурное свойство, которое вызывается при заполнении парамтеров
      запроса. При необходимости подменяется другой процедурой, а строка
      SelectAllString для того что бы можно было варьировать запрос для отбора
      элементов в список, инициализируются в конструкторе}
    property OnFillParams: TFillParamsProc read FOnFillParams
      write SetOnFillParams;
      {Ссылка на значения параметров используемых при заполнении параметров
      SQL - запроса, необходимо создавать либо структуру либо класс,
      записывать в указатель ссылку на него, при заполнении параметров извлекать
      из указателя значения , и при завершении работы класса освобождать ресурсы
      }
    property ExternalParams: Pointer read FExternalParams
      write SetExternalParams;
      {строка, которая содержит запрос для отбора идентификаторов для списка
      элементов, заполняется в конструкторе}
    property SelectAllString: string read FSelectAllString write SetSelectAllString;

  end;
{ TCommonListEngine }

function TCommonListEngine.AddItem: Pointer;
begin
  Result:= nil;
end;

procedure TCommonListEngine.ClearItems;
var
  lCommonEngine: TCommonEngine;
  i: Integer;
begin
  for i:= 0 to FItems.Count - 1 do
  begin
    lCommonEngine:= FItems[i];
    lCommonEngine.Free;
  end;
  FItems.Clear;
end;

constructor TCommonListEngine.Create;
var
  lKeyValues: PKeyValues;
begin
  inherited Create;
  FItems:= TList.Create;
  New(lKeyValues);
  ExternalParams:= lKeyValues;
end;

function TCommonListEngine.Delete: Boolean;
var
  i: Integer;
  lCommonEngine: TCommonEngine;
begin
  for i:= 0 to FItems.Count - 1 do
  begin
    lCommonEngine:= FItems[i];
    lCommonEngine.isDeleted:= True;
    Result:= lCommonEngine.Save;
  end;
  ClearItems;
end;

function TCommonListEngine.DeleteItem(AIndex: Integer): Boolean;
var
  lCommonEngine: TCommonEngine;
begin
  Result:= True;
  lCommonEngine:= FItems[AIndex];
  FItems.Delete(AIndex);
  lCommonEngine.Free;
end;

destructor TCommonListEngine.Destroy;
begin
  Dispose(ExternalParams);
  ClearItems;
  FItems.Free;
  inherited;
end;

function TCommonListEngine.FindByID(AID , ASID: Integer): TCommonEngine;
var
  lCommonEngine: TCommonEngine;
  i: Integer;
begin
  Result:= nil;
  for i:= 0 to FItems.Count - 1 do
  begin
    lCommonEngine:= FItems[i];
    if (lCommonEngine.FID = AID)
      and ((lCommonEngine.FSID = ASID) or (ASID = -1)) then begin
      Result:= lCommonEngine;
      Break;
    end;
  end;
end;

function TCommonListEngine.GetAdditionalInfo: Boolean;
begin
  Result:= inherited GetAdditionalInfo;
end;

function TCommonListEngine.GetAll: Boolean;
var
  lQuery: TADOQuery;
  lKeyValues: PKeyValues;
  lPointer: Pointer;
  lCommonObject: TCommonObject;
  i: Integer;
begin
  Result:= True;
  lQuery:= TADOQuery.Create(nil);
  with lQuery do
  try
    try
      ClearItems;
      lKeyValues:= ExternalParams;
      lKeyValues^.ID:= ID;
      lKeyValues^.SID:= SID;
      Connection:= FConnection;
      SQL.Text:= SelectAllString;
      Parameters.ParseSQL(SQL.Text, True);
      if Assigned(FOnFillParams) then
        OnFillParams(Parameters, ExternalParams);
      Open;
      First;
      while not Eof  do
      begin
        lPointer:= AddItem;
        lCommonObject:= lPointer;
        lCommonObject.FConnection:= FConnection;
        SetKeyValues(Fields, lPointer);
        Next;
      end;
      for i:= 0 to FItems.Count - 1 do
      begin
        lCommonObject:= FItems[i];
        lCommonObject.GetByID;
      end;
    Except on e: Exception do
       begin
         Result:= False;
         Raise;
       end;
    end;
  finally
    lQuery.Free;
  end;
end;

function TCommonListEngine.GetByID: Boolean;
begin
  Result:= inherited GetByID;
  GetAll;
end;

{function TCommonListEngine.GetSelectedFields(AQuery: TADOQuery): Boolean;
begin
  Result:= True;
end;}

function TCommonListEngine.Refresh: Boolean;
var
  lCommonEngine: TCommonEngine;
  i: Integer;
begin
  Result:= inherited Refresh;
  GetByID;
  GetAdditionalInfo;
  for i:= 0 to FItems.Count - 1 do
  begin
    lCommonEngine:= FItems[i];
    lCommonEngine.Fconnection:= FConnection;
    lCommonEngine.Refresh;
  end;
end;

function TCommonListEngine.Save(ASaveItems: Boolean = True): Boolean;
var
  lCommonEngine: TCommonEngine;
  i: Integer;
  lKeyValues: PKeyValues;
begin
  Result:= inherited Save(ASaveItems);
  try
    New(lKeyValues);
    lKeyValues^.ID:= ID;
    lKeyValues^.SID:= SID;
    
    for i:= 0 to FItems.Count - 1 do
    begin
      lCommonEngine:= FItems[i];
      lCommonEngine.FillForeignKey(lKeyValues);
      lCommonEngine.Save(ASaveItems);
    end;

    for i:= FItems.Count - 1 downto 0 do
    begin
      lCommonEngine:= FItems[i];
      if lCommonEngine.isDeleted then
        DeleteItem(i);
    end;
  finally
    Dispose(lKeyValues);
  end;
end;

procedure TCommonListEngine.SetExternalParams(const Value: Pointer);
begin
  FExternalParams := Value;
end;

function TCommonListEngine.SetKeyValues(AFields: TFields;
  AItem: Pointer): Boolean;
var
  lCommonObject: TCommonObject;
begin
  lCommonObject:= TCommonObject(AItem);
  with AFields do
  begin
    lCommonObject.FID:= FieldByName('id').AsInteger;
  end;
end;

procedure TCommonListEngine.SetOnFillParams(const Value: TFillParamsProc);
begin
  FOnFillParams := Value;
end;

procedure TCommonListEngine.SetSelectAllString(const Value: string);
begin
  FSelectAllString := Value;
end;
Share

Tags: , , , ,

3 Responses to “Object-relational mapping класс для работы с базой данных – TCommonListEngine”

  1. SpecAgent пишет:

    Мне все понравилось

  2. на практике пробовали использовать ?

  3. [...] статьях были предложены базовые классы: TCommonDocument, TCommonListEngine, TCommonEngine, TCommonObject и рассмотрены общие сведения о [...]

Leave a Reply