我在Delphi中使用查询获取数据,并希望在运行之前向查询添加计算字段。计算字段使用代码中的值以及查询,因此我不能仅在SQL中计算它。
我知道我可以附加一个OnCalcFields
事件来实际进行计算,但问题是在添加计算字段后,查询中没有其他字段......
我做了一些挖掘,发现所有的字段定义都已创建,但实际的字段只是创建了
if DefaultFields then
CreateFields
指定了默认字段
procedure TDataSet.DoInternalOpen;
begin
FDefaultFields := FieldCount = 0;
...
end;
这表示如果添加字段,则只会获得您添加的字段。
我希望查询中的所有字段与我添加的字段一样。
这是可能的,还是我必须添加我正在使用的所有字段?
答案 0 :(得分:11)
没有什么能阻止您在代码中首先创建所有字段,
然后添加您计算的字段。
您可以使用“黑客类型”来使用受保护的CreateFields:
type
THackQuery = class(TADOQuery)
end;
[...]
MyQuery.FieldDefs.Update;
THackQuery(MyQuery).CreateFields;
或从CreateFields借用一些代码:
MyQuery.FieldDefs.Update;
// create all defaults fields
for I := 0 to MyQuery.FieldDefList.Count - 1 do
with MyQuery.FieldDefList[I] do
if (DataType <> ftUnknown) and not (DataType in ObjectFieldTypes) and
not ((faHiddenCol in Attributes) and not MyQuery.FIeldDefs.HiddenFields) then
CreateField(Self, nil, MyQuery.FieldDefList.Strings[I]);
然后创建计算字段:
MyQueryMyField := TStringField.Create(MyQuery);
with MyQueryMyField do
begin
Name := 'MyQueryMyField';
FieldKind := fkCalculated;
FieldName := 'MyField';
Size := 10;
DataSet := MyQuery;
end;
答案 1 :(得分:3)
除了计算字段外,您还需要添加所有字段。
添加字段后,您必须在数据集中添加所需的所有字段。
Delphi将此持久字段与动态字段进行对称。所有字段都是持久的或动态的。不幸的是,你不能混合使用两者。
另外需要注意的是,文档是
持久字段组件列表是 存储在您的应用程序中,而不是 即使结构改变了 数据集底层的数据库是 改变。
因此,请注意,如果稍后向表中添加其他字段,则需要将新字段添加到组件中。删除字段也是一样。
如果你真的不想要持久字段,还有另一种解决方案。在应显示计算字段的任何网格或控件上,您可以自定义绘制它。例如,许多网格控件都有一个OnCustomDraw事件。你可以在那里进行计算。
答案 2 :(得分:1)
如果您知道在运行时计算字段名称,则可以使用类似的名称。
var
initing:boolean;
procedure TSampleForm.dsSampleAfterOpen(
DataSet: TDataSet);
var
i:integer;
dmp:tfield;
begin
if not initing then
try
initing:=true;
dataset.active:=false;
dataset.FieldDefs.Update;
for i:=0 to dataset.FieldDefs.Count-1 do
begin
dmp:=DataSet.FieldDefs.Items[i].FieldClass.Create(self);
dmp.FieldName:=DataSet.FieldDefs.Items[i].DisplayName;
dmp.DataSet:=dataset;
if (dmp.fieldname='txtState') or (dmp.FieldName='txtOldState') then
begin
dmp.Calculated:=true;
dmp.DisplayWidth:=255;
dmp.size:=255;
end;
end;
dataset.active:=true;
finally
initing:=false;
end;
end;
procedure TSampleForm.dsSampleAfterClose(
DataSet: TDataSet);
var
i:integer;
dmp:TField;
begin
if not initing then
begin
for i:=DataSet.FieldCount-1 downto 0 do
begin
dmp:=pointer(DataSet.Fields.Fields[i]);
DataSet.Fields.Fields[i].DataSet:=nil;
freeandnil(dmp);
end;
DataSet.FieldDefs.Clear;
end;
end;
procedure TSampleForm.dsSampleCalcFields(
DataSet: TDataSet);
var
tmpdurum,tmpOldDurum:integer;
begin
if not initing then
begin
tmpDurum := dataset.FieldByName( 'state' ).AsInteger;
tmpOldDurum:= dataset.FieldByName( 'oldstate' ).AsInteger;
dataset.FieldByName( 'txtState' ).AsString := State2Text(tmpDurum);
dataset.FieldByName( 'txtOldState' ).AsString := State2Text(tmpOldDurum);
end;
end;
procedure TSampleForm.btnOpenClick(Sender: TObject);
begin
if dsSample.Active then
dsSample.Close;
dsSample.SQL.text:='select id,state,oldstate,"" as txtState,"" as txtOldState from states where active=1';
dsSample.Open;
end;
答案 3 :(得分:0)
Delphi现在可以选择将自动生成的字段和计算字段组合在一起:Data.DB.TFieldOptions.AutoCreateMode类型为TFieldsAutoCreationMode的枚举。这样,您可以在运行时添加计算字段。弗朗索瓦在他的回答中写道如何在运行时添加一个字段。
TFieldsAutoCreationMode的不同模式:
<强> acExclusive 强>
如果根本没有持久字段,则会创建自动字段。这是默认模式。
<强> acCombineComputed 强>
当数据集没有持久字段或只有计算的持久字段时,将创建自动字段。这是在设计时创建持久计算字段并让数据集创建自动数据字段的便捷方式。
<强> acCombineAlways 强>
当没有持久字段时,将创建数据库字段的自动字段。