Я получаю данные с помощью запроса в Delphi и хотел бы добавить вычисляемое поле к запросу, прежде чем это будет работать. Вычисляемое поле использует значения в коде, а также запросе, таким образом, я не могу только вычислить его в SQL.
Я знаю, что могу присоединить OnCalcFields
Событие для фактического создания вычисления, но проблемы после добавляет вычисляемое поле в запросе нет никаких других полей...
Я сделал некоторое рытье и нашел, что все поле defs создается, но фактические поля только создаются
if DefaultFields then
CreateFields
Поля по умолчанию указаны
procedure TDataSet.DoInternalOpen;
begin
FDefaultFields := FieldCount = 0;
...
end;
Который указал бы, что, если Вы добавляете поля, Вы только получаете поля, Вы добавили.
Я хотел бы все поля в запросе, А ТАКЖЕ те я Добавляю.
Это возможно, или я должен добавить все поля, которые я использую также?
Вам необходимо добавить все поля в дополнение к вычисляемому полю.
После добавления поля вы должны добавить все поля, которые вы хотите, в набор данных.
Delphi называет это постоянными полями вместо динамических. Все поля могут быть постоянными или динамическими. К сожалению, нельзя сочетать и то, и другое.
Еще одна вещь, на которую следует обратить внимание, из документации:
Списки компонентов постоянных полей хранятся в вашем приложении и не меняются, даже если структура база данных, лежащая в основе набора данных, изменена.
Итак, будьте осторожны, если вы позже добавите дополнительные поля в таблицу, вам нужно будет добавить новые поля в компонент. То же самое и с удалением полей.
Если вам действительно не нужны постоянные поля, есть другое решение. В любой сетке или элементе управления, которые должны отображать вычисляемое поле, вы можете нарисовать его самостоятельно. Например, многие элементы управления сеткой имеют событие OnCustomDraw. Вы можете сделать там свой расчет.
Если вы знаете имена полей, которые будут вычисляться во время выполнения, вы можете использовать что-то подобное.
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;
Ничто не мешает вам сначала создать все поля в коде,
затем добавить вычисляемые поля.
Вы можете использовать «взломанный тип» для использования защищенных 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;