Delphi:从 IBO 迁移到 FireDac

Posted

技术标签:

【中文标题】Delphi:从 IBO 迁移到 FireDac【英文标题】:Delphi: Migrating from IBO to FireDac 【发布时间】:2015-11-10 19:13:55 【问题描述】:

所以,最近我们(我和我的同事)一直在谈论迁移到 FireDac,我们目前正在使用 IBO 和 DBX,但主要是 IBO。然后我们决定从 IBO 到 FireDac,但是输入每一个表单,更改每一个 IBOQuery,添加所有字段,设置所有显示格式等等,等等等等,都需要太多时间,所以我们决定做一个组件做到这一点,似乎是一件容易的事,但我刚刚开始,我已经陷入了一些看似简单但我以前从未遇到过的事情。先来看下组件代码:

    unit UMyComponent;

    interface

    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IB_Components, IB_Access,
      IBODataset, Vcl.StdCtrls, Vcl.Buttons, Vcl.Grids, Vcl.DBGrids, Data.DB,
      uADStanIntf, uADStanOption, uADStanParam, uADStanError,
      uADDatSManager, uADPhysIntf, uADDAptIntf, uADStanAsync, uADDAptManager,
      uADCompDataSet, uADCompClient;

    type
      TMyComponent = class(TComponent)
      private
        FADConnection: TADConnection;
        FConverter: String;

        procedure Iniciar;

        procedure SetADConnection(const Value: TADConnection);
        procedure SetConverter(const Value: String);
      published
        property Converter: String read FConverter write SetConverter;
        property ADConnection: TADConnection read FADConnection write SetADConnection;
      end;

    procedure Register;

    implementation

    procedure Register;
    begin
      RegisterComponents('MyComponents', [TMyComponent]);
    end;

     TMyComponent 

    procedure TMyComponent.Iniciar;
    var
      Form: TForm;
      IBOQuery: TIBOQuery;
      i: Integer;

      procedure _ConverterIBOQuery;
      var
        ADQuery: TADQuery;
        qName: String;
      begin
        qName := IBOQuery.Name;

        if qName.Contains('OLD_') then
          Exit;

        IBOQuery.Name := 'OLD_'+ qName;

        if (FindComponent(qName) = nil) then
        begin
          ADQuery            := TADQuery.Create(Form);
          ADQuery.Name       := qName;
          ADQuery.Connection := FADConnection;
          ADQuery.SQL        := IBOQuery.SQL;

          
           I need to add the fields here, but I need them having a reference,
           like the ones you Right Click > Fields Editor > Add All Fields (CTRL + F)
           because in the final form of this component, it won't rename the old query
           with an 'OLD_' prefix, it will destroy it, and the fields will be gone too,
           so I need to add them (having the reference) in order to not rewrite any of my code
          
        end;
      end;
    begin
      if Owner is TForm then
        Form := TForm(Owner);

      if Assigned(Form) then
      begin
        for i := 0 to (Form.ComponentCount -1) do
          
           I know it will stop in the first query it come across,
           but I'm trying to full convert only one to know if it's actually possible
          
          if (Form.Components[i] is TIBOQuery) then
          begin
            IBOQuery := TIBOQuery(Form.Components[i]);
            Break;
          end;

        if Assigned(IBOQuery) then
          _ConverterIBOQuery;
      end;
    end;

    procedure TMyComponent.SetConverter(const Value: String);
    begin
      FConverter := UpperCase(Value[1]);

      if (FConverter = 'S') then
        Iniciar;

      FConverter := '';
    end;

    procedure TMyComponent.SetADConnection(const Value: TADConnection);
    begin
      FADConnection := Value;
    end;

    end.

我已经尝试了一些在网上找到的方法,例如:

创建TField的变量 使用 FieldDefs/FieldDefList,更新它们并创建字段 使用“假”类“入侵”ADQuery,以便使用 CreateFields 过程

他们都没有达到我的预期,所以我在质疑

我可以通过代码创建字段引用吗?而且,如果可能的话,怎么做?

我的意思是,例如,您有 IBOQuery1,而 SQL 是

SELECT NAME
FROM COUNTRY

之后,您转到字段编辑器 > 添加所有字段 (CTRL + F),然后您有引用 IBOQuery1NAME,它是一个 TStringField,您可以只调用 IBOQuery1NAME.AsString 而不是 IBOQuery1.FieldByName('NAME ').AsString

TL;DR

尝试创建将 IBOQuery 迁移到 ADQuery 的组件,但我无法创建引用

【问题讨论】:

"将 IBOQuery 迁移到 ADQuery 的组件" 嗯,FireDAC 有它的 TFDBatchMove 组件来协助处理这类事情。你看过吗? 似乎它只适用于XE7或更高版本,不幸的是,我正在使用XE3,但经过简短阅读后,它并不是我想要的。我会继续调查它,也许是我的阅读有问题,但似乎不是我的预期。 嗯,你可以用代码复制表格数据。如何做到最好取决于涉及多少数据行。几千与几百万是完全不同的问题。你有多少?无论如何,如果您将 Ado 与 Sql Server 后端一起使用,我建议您考虑使用 Delphi 的标准 Ado 组件而不是 FireDAC。如果您不需要 FireDAC 的一些更神秘的功能,那么 FireDAC 对所有人的一切的追求以及它可能涉及的抽象级别有时会妨碍您。 平均每个查询大约有 100 行,每个表单平均有 3 个查询,我们已经考虑过以这种方式进行复制,但是如果我们可以像添加它们那样添加它们(不复制代码),那就更好了 【参考方案1】:

经过多次尝试和研究,我发现了一个与我的问题相似的老问题,很高兴有一个正是我想要的答案

How to add a field programatically to a TAdoTable in Delphi

答案由用户提供:Мסž

procedure AddAllFields(DataSet: TDataset);
var
   FieldsList: TStringList;
   FieldName: WideString;
   Field: TField;
   WasActive: boolean;
   FieldDef: TFieldDef;
   i: Integer;
begin
   WasActive := DataSet.Active;
   if WasActive then
      DataSet.Active := False;
   try
      FieldsList := TStringList.Create;
      try
         DataSet.FieldDefs.Update;

         // make a list of all the field names that aren't already on the DataSet
         for i := 0 to DataSet.FieldDefList.Count - 1 do
            with DataSet.FieldDefList[i] do
               if (FieldClass <> nil) and not(faHiddenCol in Attributes) then
               begin
                  FieldName := DataSet.FieldDefList.Strings[i];
                  Field := DataSet.FindField(FieldName);
                  if (Field = nil) or (Field.Owner <> DataSet.Owner) then
                     FieldsList.Add(FieldName);
               end;

         // add those fields to the dataset
         for i := 0 to FieldsList.Count - 1 do
         begin
            FieldDef := DataSet.FieldDefList.FieldByName(FieldName);
            Field := FieldDef.CreateField(DataSet.Owner, nil, FieldName, False);
            try
               Field.name := FieldName + IntToStr(random(MaxInt)); // make the name unique
            except
               Field.Free;
               raise ;
            end;
         end;
      finally
         FieldsList.Free;
      end;
   finally
      if WasActive then
         DataSet.Active := true;
   end;
end;

【讨论】:

我的最终版本有一些修改,因为它没有按我想要的 100% 工作,但它首先做了我需要的,所以我很感激我找到了它

以上是关于Delphi:从 IBO 迁移到 FireDac的主要内容,如果未能解决你的问题,请参考以下文章

将记录从一个 db 迁移到 mysql 使用 Delphi 和 Firedac 非常慢

delphi 各新版本特性收集

如何优化 VBO/IBO 以最大化 GPU 缓存使用率

冻结 Indy HTTP。进入 Android Delphi 11 内部线程

为啥使用 VBO 和/或 IBO 而不是简单的顶点数据?

VAO 中的 C++ GLSL 多个 IBO