Delphi:从 IBO 迁移到 FireDac
Delphi: Migrating from IBO to FireDac
所以,最近我们(我和我的同事)一直在谈论迁移到 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,更新它们并创建字段
- "Hacking" ADQuery 加上 "fake" class 为了使用
CreateFields 程序
其中 none 达到了我的预期,所以我在质疑
Can I create the field references via code? And, if it's possible, how?
我的意思是引用,例如,您有 IBOQuery1,SQL 是
SELECT NAME
FROM COUNTRY
之后,您转到字段编辑器 > 添加所有字段 (CTRL + F),然后您有引用 IBOQuery1NAME,它是一个 TStringField,您可以调用 IBOQuery1NAME.AsString 而不是 IBOQuery1.FieldByName('NAME').AsString
TL;DR
试图创建一个将 IBOQuery 迁移到 ADQuery 的组件,但我无法创建引用
经过多次尝试和研究,我发现了一个和我问题相似的老问题,很高兴得到了我想要的答案
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;
所以,最近我们(我和我的同事)一直在谈论迁移到 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,更新它们并创建字段
- "Hacking" ADQuery 加上 "fake" class 为了使用 CreateFields 程序
其中 none 达到了我的预期,所以我在质疑
Can I create the field references via code? And, if it's possible, how?
我的意思是引用,例如,您有 IBOQuery1,SQL 是
SELECT NAME
FROM COUNTRY
之后,您转到字段编辑器 > 添加所有字段 (CTRL + F),然后您有引用 IBOQuery1NAME,它是一个 TStringField,您可以调用 IBOQuery1NAME.AsString 而不是 IBOQuery1.FieldByName('NAME').AsString
TL;DR
试图创建一个将 IBOQuery 迁移到 ADQuery 的组件,但我无法创建引用
经过多次尝试和研究,我发现了一个和我问题相似的老问题,很高兴得到了我想要的答案
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;