Добавление вычисляемого поля к Запросу во время выполнения

Я получаю данные с помощью запроса в Delphi и хотел бы добавить вычисляемое поле к запросу, прежде чем это будет работать. Вычисляемое поле использует значения в коде, а также запросе, таким образом, я не могу только вычислить его в SQL.

Я знаю, что могу присоединить OnCalcFields Событие для фактического создания вычисления, но проблемы после добавляет вычисляемое поле в запросе нет никаких других полей...

Я сделал некоторое рытье и нашел, что все поле defs создается, но фактические поля только создаются

if DefaultFields then
    CreateFields

Поля по умолчанию указаны

procedure TDataSet.DoInternalOpen;
begin
    FDefaultFields := FieldCount = 0;
    ...
end;

Который указал бы, что, если Вы добавляете поля, Вы только получаете поля, Вы добавили.

Я хотел бы все поля в запросе, А ТАКЖЕ те я Добавляю.

Это возможно, или я должен добавить все поля, которые я использую также?

9
задан James Barrass 26 March 2010 в 13:50
поделиться

3 ответа

Вам необходимо добавить все поля в дополнение к вычисляемому полю.

После добавления поля вы должны добавить все поля, которые вы хотите, в набор данных.

Delphi называет это постоянными полями вместо динамических. Все поля могут быть постоянными или динамическими. К сожалению, нельзя сочетать и то, и другое.

Еще одна вещь, на которую следует обратить внимание, из документации:

Списки компонентов постоянных полей хранятся в вашем приложении и не меняются, даже если структура база данных, лежащая в основе набора данных, изменена.

Итак, будьте осторожны, если вы позже добавите дополнительные поля в таблицу, вам нужно будет добавить новые поля в компонент. То же самое и с удалением полей.

Если вам действительно не нужны постоянные поля, есть другое решение. В любой сетке или элементе управления, которые должны отображать вычисляемое поле, вы можете нарисовать его самостоятельно. Например, многие элементы управления сеткой имеют событие OnCustomDraw. Вы можете сделать там свой расчет.

3
ответ дан 4 December 2019 в 11:41
поделиться

Если вы знаете имена полей, которые будут вычисляться во время выполнения, вы можете использовать что-то подобное.

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;
1
ответ дан 4 December 2019 в 11:41
поделиться

Ничто не мешает вам сначала создать все поля в коде,
затем добавить вычисляемые поля.

Вы можете использовать «взломанный тип» для использования защищенных 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;
12
ответ дан 4 December 2019 в 11:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: