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

При работе базой данных часто происходит обращение к одним и тем же таблицам из разных форм и программных модулей. Во избежание дублирования SQL – запросов, а так же удобства работы с сущностями в программном коде был создан общей класс (шаблон), который реализует работу как с одиночными записями, списками одиночных записей и объединениями одиночных записей и списков одиночных записей, привязанных или не привязанных к единичным записям. Как правило, такими структурами являются документы, в которых заголовок и строки принадлежат к различным типам единичных записей. В общем случае это есть Object-relational mappin. Данная статья существенная переработка шаблона предложенного в пред идущей статье Delphi Базовый класс для Model-view-controller.

Общие сведения.

 

В статье будут даны общие сведения о базовом классе и его устройстве. Базовый класс описан в модуле uCommonEngine.pas. В нем реализованный следующие классы :

– TCommonObject – базовый класс реализующий общие для все классов методы для доступа к базе данных общие поля , а так же задает виртуальные методы для других методов не связанных с реализацией доступа к базе данных;

– TCommonEngine – наследуется от TCommonObject и реализует шаблон доступ к единичной записи в таблице базы данных его наследники реализуют дополнительные методы, связанные с обработкой единичной записи в ходе работы приложения а так же содержат данные для получения значений полей из базы;

– TCommonListEngine – наследуется от TCommonObject и реализует шаблон доступа к списку единичных записей в таблице;

– TCommonDocument – наследуется от TCommonObject и реализует шаблон доступа к объединению единичных записей и привязанным или не привязанным к ним спискам единичных записей, наследники реализуют методы прописывания ключевых полей и дополнительные методы обработки объединений единичных записей и списков единичных записей.

TKeyValues – структура для хранения значений ключевых полей;

PKeyValues – указатель на структура соответствующего типа;

TFillParamsProc – процедурный тип, для хранения указателя на метод класса который будет заполнять параметры запроса в качестве параметров принимает ссылку на список параметров TParameters и указатель на структуру содержащую параметры запрос;

Заметим, что в качестве параметров можно передавать произвольный список параметров и указатель на произвольную структуру значений параметров, заполнение которых реализует процедура заполнения, которая содержится в указателе на процедуру TFillParamsProc;

TOnSetKeyValue – процедурный тип, который указывает на функция, которая будет вызываться для заполнения полей внешнего ключа при работе со списками единичных записей и сложных объединений;

TOnRefresh – процедурный тип, содержащий указатель на функцию, в которой содержится указатель на функцию, которая вызывается при выполнении метода Refresh.


interface
uses ADODB, DB, Classes, SysUtils;
type

  TKeyValues = packed record
    ID: Integer;
    SID: Integer;
  end;

  PKeyValues = ^TKeyValues;
    { Процедурный типа для подстановки процедуры заполенения параметров при
    изменении общего методада выбори всех данных для списка объектов}
  TFillParamsProc = procedure (AParams: TParameters;
    AParamValues: Pointer) of object;
  {Общий метод вызываемый после обновления объекта}
  TOnRefresh = function : Boolean of object;
    {Общий метод вызываемый после Установки ключевого поля, необходим при работе
    с документами}
  TOnSetKeyValue = function : Boolean of object;
    {Общий метод для заполнения параметров SQL запроса к базе данных }
  TFillForeignKey = function (AForeignCodeValues: Pointer) : Boolean of object;

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

unit uCommonEngine;
{*******************************************************************************
*   Базовые классы сожержаште соновные методы для работыы с значениями из БД.
* Позволяет создавать как единичные экземпляры классав, так и списки. Так же
* возможно создниае срутктур вида "Документ" с заголовкам и списком строк. Для
* этого от  TCommonEngine наследуется класс TDocXXX в котором ключевые поля
* заполняются ключевыми полями заголовка документа, и внем создаются два
* экземпляра класса типа заголовок документа и строки документа. Все процедуры
* TDocXXX следует перегрузить с тем расчетом, что бы они обеспечивали
* согласование заголовка и строк документа (получение данны, сохранение,
* удаление и т.д. ).
*******************************************************************************}
interface
  uses ADODB, DB, Classes, SysUtils;
type

  TKeyValues = packed record
    ID: Integer;
    SID: Integer;
  end;

  PKeyValues = ^TKeyValues;
    { Процедурный типа для подстановки процедуры заполенения параметров при
     изменении общего методада выбори всех данных для списка объектов}
  TFillParamsProc = procedure (AParams: TParameters;
    AParamValues: Pointer) of object;
    {Общий метод вызываемый после обновления объекта}
  TOnRefresh = function : Boolean of object;
    {Общий метод вызываемый после Установки ключевого поля, необходим при работе
     с документами}
  TOnSetKeyValue = function : Boolean of object;
    {Базовая }
  TFillForeignKey = function (AForeignCodeValues: Pointer) : Boolean of object;

    {Базовый класс для всех объектов базы данных}
  TCommonObject = class
  private
    FisDeleted: Boolean;
    FSID: Integer;
    FID: Integer;
    FAfterOnRefresh: TOnRefresh;
    FOnSetKayValue: TOnSetKeyValue;
    procedure SetID(const Value: Integer);
    procedure SetisDeleted(const Value: Boolean);
    procedure SetSID(const Value: Integer);
    procedure SetAfterOnRefresh(const Value: TOnRefresh);
    procedure SetOnSetKayValue(const Value: TOnSetKeyValue);
  public
    FConnection: TADOConnection;
      {Идентификатор записи }
    property ID: Integer read FID write SetID;
      {Идентификатор станции записи }
    property SID: Integer read FSID Write SetSID;
      {Признак того что экземпляр класса удален и при выполнении процедуры Save
      будет вызвана процедура Delete}
    property isDeleted: Boolean read FisDeleted write SetisDeleted;
      {свойоство вызываемое после обновления объекта}
    property AfterOnRefresh: TOnRefresh read FAfterOnRefresh
      write SetAfterOnRefresh;
      {Метод вызываемый при уставноки значений ключевого поля}
    property OnSetKayValue: TOnSetKeyValue read FOnSetKayValue
      write SetOnSetKayValue;
      {Конструктор при необходимости перегружается в наследуеміх классах }
    constructor Create;virtual;
      {Общий метод сохранения, вставляет обновляет и удаляет записи в
       зависимости от состояния isDeleted и ID}
    function Save(ASaveItems: Boolean = True): Boolean;virtual;
      {Общий метод удаления}
    function Delete: Boolean;virtual;
      {общий метод выбора из базы данных }
    function GetByID: Boolean;virtual;
      {Обновление элементов из базы данных}
    function Refresh:Boolean;virtual;
      {Общий метод заполнения дополнительной иорфмации объекта}
    function GetAdditionalInfo: Boolean; virtual;
      {Функция для заполнения значений внешнего ключа}
    function FillForeignKey(AForeignCodeValues: Pointer): Boolean;virtual;
  end;

    {Базовый класс для всех объектов базы данных}
  TCommonDocument = class(TCommonObject)
  private
  public
      {Список заголовков объектов, из которых состоит документ на первом месте
       должен быть тот объект который является ключевым для всего документа }
    FObjectList: TList;
      {Список строк заголовков объектов, из которых состоит документ на первом
       месте должен быть тот объект который является ключевым для всего
       документа }
    FObjectItemList: TList;
      {конструктор наследуется от базового класса и при перегрузке должен быть
        дополнен командой inherited }
    constructor Create;override;
      {Деструктор в случае необходимости перегружается в наследуемом классе
        и при перегрузке должен быть дополнен командой inherited }
    destructor Destroy;virtual;
      {Общий метод сохранения , сохраняет все объекты заголовки, которые есть в
      списке и их строки в зависимости от условия ASaveItems}
    function Save(ASaveItems: Boolean = True): Boolean;override;
      {Общий метод удаления, устанавливает всем объектам свойство
       isDeleted = True после чего сохраняет все объекты}
    function Delete: Boolean;override;
      {выбирает все объекты по ключевым полям из базы данных }
    function GetByID: Boolean;override;
      {Обновляет все оббъекты данными из базы данных}
    function Refresh:Boolean;override;
      {Заполняет дополнительную информацию для документа }
    function GetAdditionalInfo: Boolean; override;
      {Функция для устанвоки свойств соединения с базой данных}
    function SetAllConnection: Boolean;virtual;
      {Устанавливает значения всем ключевым }
    function SetKeyValuesAll: Boolean;virtual;
      {Устанавливает значения ключевым полям документа}
    function SetKeyValuesInHeaders: Boolean;virtual;
      {Устанавливает значения ключевым полям строкам документа}
    function SetKeyValuesInItems: Boolean;virtual;
      {Очщает все строки объектов}
    function ClearObjectList: Boolean;
    function ClearObjectItemList: Boolean;
  end;

    {Класс для единичной записи из БД.}
  TCommonEngine = class(TCommonObject)
  private
    FUpDateString: string;
    FInsertString: string;
    FTableName: string;
    FSelectString: string;
    FDeleteString: string;
    procedure SetInsertString(const Value: string);
    procedure SetUpDateString(const Value: string);
    procedure SetTableName(const Value: string);
    procedure SetSelectString(const Value: string);
    procedure SetDeleteString(const Value: string);
  public
      {Конструктор, в нем
        инициализируются
        isDeleted:= False
        ID:= -1
        Поэтому обязательно писать в наследуемом классе

        inherited Create;

        заполняются свойства
        - TableName
        - InsertString
        - UpDateString
        - SelectString
        - DeleteString }
    constructor Create;override;
      {Выполняет выбор значений из БД. Перед візовом не обходимо заполнять ключевіе поля.
       Вызывает процедуры
        - GetSelectedFields
        - FillParametersSelectOrdelete

      Имеет смысл
      заполнять в наследуемом классе

      Result:= inherited GetByID;
      }
    function GetByID: Boolean; override;
      {Выполняет заполеннеи свойств класса значениями из полей, которые
      возврщаются из БД при выполнении запроса SelectString. Имеет смысл
      заполнять в наследуемом классе

      Result:= inherited GetSelectedFields(AFields)
      }
    function GetSelectedFields(AFields: TFields): Boolean; virtual;
      {Выполняет заполенение свойств , которые не выбираются из таблицы, которая
      записана в свойстве TableName, или же они вычисляются на основе существующих
      свойств. вызывается не зависомо от GetByID, но не ранее т.к. все остальные
      свойства могут быть не заполнены. Имеет смысл
      заполнять в наследуемом классе

      Result:= inherited GetAdditionalInfo;
      }
    function GetAdditionalInfo: Boolean; override;
      {Выполняет вставку в таблицу записи, вней же происходит дополнение
      InsertString параметром id и возврат этого параметра в свойство класса
      id идентификтаора вставленной записи. Параметры для вставки берутся из
      соотвествующих свойств наследуемого класса и запонюябтсяони в процедуре
      FillParamsInsertOrUpdate используя параметр AParameters. Значение id
      заполнять не нужно, оно будет заполнено автоматически. Если при вставке
      не требутся делать каких-либо дополниеьтльных действий, то в наслеудемо
      классе имеет смысл заполнить данную процедуру следующим кодом

      Result:= inherited Insert;
      }
    function Insert: Boolean; virtual;
      {Выполняет обновление записи в базе данных. Параметры для вставки берутся
      из соотвествующих свойств наследуемого класса и запонюябтсяони в процедуре
      FillParamsInsertOrUpdate используя параметр AParameters. Значение id
      заполнять не нужно, оно будет заполнено автоматически. Если при вставке
      не требутся делать каких-либо дополнительных действий, то в наслеудемо
      классе имеет смысл заполнить данную процедуру следующим кодом, если не
      требуется выполнять никаких дополнительных действий

      Result:= inherited Update;
      }
    function Update: Boolean; virtual;
      {Выполняет удаление записи из базы данных вне зависимости от значения
      свойства isDeleted. Параметры для удаления заполняются в процедуре
      FillParametersSelectOrdelete
      В наслеудемо классе имеет смысл заполнить данную процедуру следующим кодом,
      если не требуется выполнять никаких дополнительных действий

      Result:= inherrited Delete
      }
    function Delete: Boolean; override;
      {Выполняет сохранение класс по его параметрам.
      Если установлено true свойство isDeleted, то вызывается процедура Delete,
      в противном случае если id > 0, то вызывается процедура Update.
      В наслеудемо классе имеет смысл заполнить данную процедуру следующим кодом,
      если не требуется выполнять никаких дополнительных действий

      Result:= inherrited Save;
      }

    function Save(ASaveItems: Boolean = True): Boolean; override;
      {Заполняем параметры отличне от id значениями свойтсв класса при вставке
      или обновлении  записи }
    function FillParamsInsertOrUpdate(AParameters: TParameters): Boolean; virtual;
      {Заполняем параметры отличне от id значениями свойтсв класса}
    function FillParametersSelectOrdelete(AParameters: TParameters): Boolean; virtual;
      {обновляет поля в классе данными из базы}
    function Refresh: Boolean;override;
      {строка содержащая SQL - запрос для вставки одной зааписи в БД.
       Поле id не надо указывать в запросе, оно будет добавлено при выполнении
       запроса и заполнено идентификатором вставленной записи, и возвращено в
       свойство класса ID, идентификатор вставленной записи определяется по
       свойству  TableName. Данная строка заполняется в конструкторе
       наследуемого класса.}
    property InsertString: string read FInsertString write SetInsertString;
      {строка содержащая SQL - запрос для обновления одной зааписи в БД. Данная
       строка заполняется в конструкторе наследуемого класса.}
    property UpDateString: string read FUpDateString write SetUpDateString;
      {строка содержащая SQL - запрос для обновления одной зааписи в БД. Данная
       строка заполняется в конструкторе наследуемого класса.}
    property SelectString: string read FSelectString write SetSelectString;
      {строка содержащая SQL - запрос для удаления одной зааписи в БД. Данная
       строка заполняется в конструкторе наследуемого класса.}
    property DeleteString: string read FDeleteString write SetDeleteString;
      {Название табилцы БД, в которой хранятся записи для создаваемого класса.
       Заполняется в конструкторе класса.}
    property TableName: string read FTableName write SetTableName;
   {--------------------------------------------------------------------------}
  end;

    {Для списка значией обного типа из списка базы даннаан. Перед описанием
    списка элементов необходимо описать класс единичных записей списка }

  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;

implementation

{ TCommonEngine }

constructor TCommonEngine.Create;
begin
  inherited Create;
end;

function TCommonEngine.Delete: Boolean;
begin
  Result:= inherited Delete;
  with TADOCommand.Create(nil) do
  try
    Connection:= Fconnection;
    CommandText:= DeleteString;
    Parameters.ParseSQL(CommandText, True);
    FillParametersSelectOrdelete(Parameters);
    Execute;
  finally
    Free;
  end;
end;

function TCommonEngine.FillParametersSelectOrdelete(
  AParameters: TParameters): Boolean;
begin
  with AParameters do
  begin
    ParamByName('id').DataType:= ftInteger;
    ParamByName('id').Value:= ID;
  end;
end;

function TCommonEngine.FillParamsInsertOrUpdate(AParameters: TParameters): Boolean;
begin
  Result:= True;
  with AParameters do
  begin
    ParamByName('id').DataType:= ftInteger;
    ParamByName('id').Value:= ID;
    if ID  0 then  Result:= Update
    else Result:= Insert;
end;

procedure TCommonEngine.SetDeleteString(const Value: string);
begin
  FDeleteString := Value;
end;

procedure TCommonEngine.SetInsertString(const Value: string);
begin
  FInsertString := Value;
end;

procedure TCommonEngine.SetSelectString(const Value: string);
begin
  FSelectString := Value;
end;

procedure TCommonEngine.SetTableName(const Value: string);
begin
  FTableName := Value;
end;

procedure TCommonEngine.SetUpDateString(const Value: string);
begin
  FUpDateString := Value;
end;

function TCommonEngine.Update: Boolean;
begin
  Result:= True;
  with TADOCommand.Create(nil) do
  try
    Connection:= Fconnection;
    CommandText:= UpDateString;
    Parameters.ParseSQL(CommandText, True);
    FillParamsInsertOrUpdate(Parameters);
    Execute;
  finally
    Free;
  end;
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;

{ TCommonObject }

constructor TCommonObject.Create;
begin
  FisDeleted:= False;
  FID:= -1;
  FSID:= -1;
end;

function TCommonObject.Delete: Boolean;
begin
  Result:= True;
end;

function TCommonObject.FillForeignKey(AForeignCodeValues: Pointer): Boolean;
begin
  Result:= True;
end;

function TCommonObject.GetAdditionalInfo: Boolean;
begin
  Result:= True;
end;

function TCommonObject.GetByID: Boolean;
begin
  Result:= True;
end;

function TCommonObject.Refresh: Boolean;
begin
  Result:= True;
  if Assigned(FAfterOnRefresh) then
    Result:= AfterOnRefresh;
end;

function TCommonObject.Save(ASaveItems: Boolean = True): Boolean;
begin
  Result:= True;
  if isDeleted then
    Result:= Delete;
end;

procedure TCommonObject.SetAfterOnRefresh(const Value: TOnRefresh);
begin
  FAfterOnRefresh := Value;
end;

procedure TCommonObject.SetID(const Value: Integer);
begin
  FID:= Value;
end;

procedure TCommonObject.SetisDeleted(const Value: Boolean);
begin
  FisDeleted := Value;
end;

procedure TCommonObject.SetOnSetKayValue(const Value: TOnSetKeyValue);
begin
  FOnSetKayValue := Value;
end;

procedure TCommonObject.SetSID(const Value: Integer);
begin
  FSID := Value;
end;

{ TCommonDocument }

function TCommonDocument.ClearObjectItemList: Boolean;
var
  lCommonObject: TCommonObject;
  i: Integer;
begin
  for i:= 0 to FObjectItemList.Count - 1 do
  begin
    lCommonObject:= FObjectItemList[i];
    if Assigned(lCommonObject) then
      lCommonObject.Free;
  end;
  FObjectList.Clear;
  FreeAndNil(FObjectList);
  inherited;
end;

function TCommonDocument.ClearObjectList: Boolean;
var
  lCommonObject: TCommonObject;
  i: Integer;
begin
  for i:= 0 to FObjectList.Count - 1 do
  begin
    lCommonObject:= FObjectList[i];
    if Assigned(lCommonObject) then
      lCommonObject.Free;
  end;
  FObjectList.Clear;
  FreeAndNil(FObjectList);
  inherited;
end;

constructor TCommonDocument.Create;
begin
  inherited Create;
  FObjectList:= TList.Create;
  FObjectItemList:= TList.Create;
end;

function TCommonDocument.Delete: Boolean;
var
  i: Integer;
  lCommonObject: TCommonObject;
begin
  Result:= inherited Delete;
  for I:= 0 to FObjectItemList.Count - 1 do
  begin
    lCommonObject:= FObjectItemList[i];
    if Assigned(lCommonObject) then
      lCommonObject.Delete;
  end;

  for I:= 0 to FObjectList.Count - 1 do
  begin
    lCommonObject:= FObjectList[i];
    if Assigned(lCommonObject) then
      lCommonObject.Delete;
  end;
end;

destructor TCommonDocument.Destroy;
begin
  ClearObjectList;
  ClearObjectItemList;
  inherited;
end;

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

function TCommonDocument.GetByID: Boolean;
var
  lCommonObject: TCommonObject;
  i: Integer;
begin
  Result:= inherited GetByID;
  SetAllConnection;
  if Assigned(OnSetKayValue) then
    OnSetKayValue;

  for i:= 0 to FObjectList.Count - 1 do
  begin
    lCommonObject:= FObjectList[i];
    if Assigned(lCommonObject) then begin
      lCommonObject.GetByID;
      if Assigned(lCommonObject.OnSetKayValue) then
        lCommonObject.OnSetKayValue
    end;
  end;

  for i:= 0 to FObjectItemList.Count - 1 do
  begin
    lCommonObject:= FObjectItemList[i];
    if Assigned(lCommonObject)  then
      lCommonObject.GetByID;
      if Assigned(lCommonObject.OnSetKayValue) then
        lCommonObject.OnSetKayValue
  end;
end;

function TCommonDocument.Refresh: Boolean;
var
  lCommonObject: TCommonObject;
  i: Integer;
begin
  Result:= inherited Refresh;
  SetAllConnection;
  for i:= 0 to FObjectList.Count - 1 do
  begin
    lCommonObject:= FObjectList[i];
    lCommonObject.GetByID;
    lCommonObject.GetAdditionalInfo;
  end;

  for i:= 0 to FObjectItemList.Count - 1 do
  begin
    lCommonObject:= FObjectItemList[i];
    lCommonObject.GetByID;
    lCommonObject.GetAdditionalInfo;
  end;
end;

function TCommonDocument.Save(ASaveItems: Boolean = True): Boolean;
var
  i: Integer;
  lCommonObject: TCommonObject;
begin

  if not isDeleted then begin
    for i:= 0 to FObjectList.Count - 1 do
    begin
      lCommonObject:= FObjectList[i];
      if Assigned(lCommonObject) then begin
        lCommonObject.Save(ASaveItems);
        if Assigned(lCommonObject.OnSetKayValue) then
          lCommonObject.OnSetKayValue;
      end;
    end;
    lCommonObject:= FObjectList[0];
    if Assigned(lCommonObject) then begin
      ID:= lCommonObject.ID;
      SID:= lCommonObject.SID;
    end;

    if ASaveItems then
      for i:= 0 to FObjectItemList.Count - 1 do
      begin
        lCommonObject:= FObjectItemList[i];
        if Assigned(lCommonObject) then begin
          lCommonObject.Save(ASaveItems);
          if Assigned(lCommonObject.OnSetKayValue) then
            lCommonObject.OnSetKayValue;
        end;
      end;
  end
  else begin
    if ASaveItems then
      for i:= 0 to FObjectItemList.Count - 1 do
      begin
        lCommonObject:= FObjectItemList[i];
        if Assigned(lCommonObject) then begin
          lCommonObject.Save(ASaveItems);
          if Assigned(lCommonObject.OnSetKayValue) then
            lCommonObject.OnSetKayValue;
        end;
      end;

    for i:= 0 to FObjectList.Count - 1 do
    begin
      lCommonObject:= FObjectList[i];
      if Assigned(lCommonObject) then begin
        lCommonObject.Save(ASaveItems);
        if Assigned(lCommonObject.OnSetKayValue) then
          lCommonObject.OnSetKayValue;
      end;
    end;
  end;
  Result:= inherited Save(ASaveItems);
end;

function TCommonDocument.SetAllConnection: Boolean;
var
  i: Integer;
  lCommonObject: TCommonObject;
begin
  Result:= True;
  for i:= 0 to FObjectList.Count - 1 do
  begin
    lCommonObject:= FObjectList[i];
    if Assigned(lCommonObject) then begin
      lCommonObject.FConnection:= FConnection;
      if lCommonObject is TCommonDocument then
        TCommonDocument(lCommonObject).SetAllConnection;
    end;
  end;

  for i:= 0 to FObjectItemList.Count - 1 do
  begin
    lCommonObject:= FObjectItemList[i];
    if Assigned(lCommonObject) then begin
      lCommonObject.FConnection:= FConnection;
      if lCommonObject is TCommonDocument then
        TCommonDocument(lCommonObject).SetAllConnection;
    end;
  end;
end;

function TCommonDocument.SetKeyValuesAll: Boolean;
begin
  SetKeyValuesInHeaders;
  Result:= SetKeyValuesInItems;
end;

function TCommonDocument.SetKeyValuesInHeaders: Boolean;
begin
  if Assigned(OnSetKayValue) then
    Result:= OnSetKayValue
  else
    Result:= True;
end;

function TCommonDocument.SetKeyValuesInItems: Boolean;
var
  i: Integer;
  lOnSetKeyValue: TOnSetKeyValue;
  lCommonObject: TCommonObject;
begin
  Result:= True;
//  SetKeyValuesInItems;
  SetAllConnection;
  for I:= 0 to FObjectList.Count - 1 do
  begin
    lCommonObject:= FObjectList[i];
    if Assigned(lCommonObject) then begin
      lCommonObject.FConnection:= FConnection;
      lOnSetKeyValue:= lCommonObject.FOnSetKayValue;
      if Assigned(lOnSetKeyValue) then
        lOnSetKeyValue;
    end;
  end;

  for I:= 0 to FObjectItemList.Count - 1 do
  begin
    lCommonObject:= FObjectItemList[i];
    if Assigned(lCommonObject) then
      lCommonObject.FConnection:= FConnection;
  end;
end;

end.
Share

Tags: , , , , ,

6 Responses to “Object-relational mapping класс для работы с базой данных – общие сведения”

  1. [...] Эрудиты {lang: 'ru'} « Object-relational mapping класс для работы с базой данных – общи… [...]

  2. [...] статьи Object-relational mapping класс для работы с базой данных – общи…. Подробно рассматривается базовый для всех остальных [...]

  3. [...] статьи Object-relational mapping класс для работы с базой данных – общи…. Подробно рассматривается базовый для всех остальных [...]

  4. [...] статьи Object-relational mapping класс для работы с базой данных – общи…. Подробно рассматривается базовый для всех остальных [...]

  5. [...] статьи Object-relational mapping класс для работы с базой данных – общи…. Предлагается пример реализации потомка клоссов [...]

  6. здесь пишет:

    Занятно. Подпишусь-ка я на RSS пожалуй

Leave a Reply