Frage

Ich erhalte Daten eine Abfrage in Delphi verwenden und möchte ein berechnetes Feld, um die Abfrage hinzuzufügen, bevor es ausgeführt wird. Das berechnete Feld wird auch Werte in Code verwenden als die Abfrage, so kann ich nicht einfach in SQL berechnen.

Ich weiß, ich kann ein OnCalcFields Ereignis anhängen, um tatsächlich die Berechnung zu machen, aber das Problem ist, nachdem das berechnete Feld Hinzufügen es keine anderen Felder in der Abfrage sind ...

habe ich einige graben und fand, dass alle Feld defs erstellt werden, sondern die tatsächlichen Felder werden nur erstellt

if DefaultFields then
    CreateFields

Standard Felder angegeben

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

, die anzeigen würde, dass, wenn Sie Felder hinzufügen nur die Felder erhalten Sie hinzugefügt.

Ich möchte alle die Felder in der Abfrage als auch die, die ich hinzufügen.

Ist das möglich oder muss ich fügen Sie alle Felder, die ich auch bin mit?

War es hilfreich?

Lösung

Delphi hat nun die Möglichkeit, automatisch generierte Felder zu kombinieren und berechnete Felder: Data.DB.TFieldOptions.AutoCreateMode eine Aufzählung von Typ TFieldsAutoCreationMode . Auf diese Weise können Sie Ihre berechneten Felder zur Laufzeit hinzufügen. Francois schrieb in seiner Antwort, wie ein Feld zur Laufzeit hinzuzufügen.

Verschiedene Modi von TFieldsAutoCreationMode:

  • acExclusive

    Wenn es keine persistenten Felder überhaupt, dann sind automatische Felder erstellt. Dies ist der Standardmodus.

  • acCombineComputed

    Die automatischen Felder werden erstellt, wenn der Datensatz keine persistenten Felder hat oder es werden nur persistente Felder berechnet. Dies ist eine bequeme Art und Weise die persistenten berechneten Felder zur Entwurfszeit zu erstellen und lassen Sie die Datenmenge automatische Datenfelder erstellen.

  • acCombineAlways

    Automatische Felder für die Datenbankfelder erstellt werden, wenn es keine persistenten Felder sind.

Andere Tipps

Nichts hindert Sie von der Erstellung alle Felder zunächst in Ihrem Code,
dann berechnete Felder hinzufügen.

Sie können entweder einen „gehackten Typ“ verwenden, um die geschützten Create zu verwenden:

type
  THackQuery = class(TADOQuery)
  end;
[...]
  MyQuery.FieldDefs.Update;
  THackQuery(MyQuery).CreateFields;

oder leihen einige Code von Create:

  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]);

dann erstellen Sie Ihre Felder berechnet:

  MyQueryMyField := TStringField.Create(MyQuery);
  with MyQueryMyField do
  begin
    Name := 'MyQueryMyField';
    FieldKind := fkCalculated;
    FieldName := 'MyField';
    Size := 10;
    DataSet := MyQuery;
  end;

Sie müssen alle Felder zusätzlich zu Ihrem berechneten Feld hinzuzufügen.

Wenn Sie ein Feld hinzufügen, haben Sie alle Felder hinzuzufügen, dass Sie in dem Datensatz werden sollen.

Delphi ruft diese persistenten Felder und dynamische Felder aus. Alle Felder sind entweder persistent oder dynamisch. Leider kann man nicht eine Mischung aus beidem hat.

Eine andere Sache zu beachten, von der Dokumentation ist

  

Persistent Felder Komponentenlisten sind   in Ihrer Anwendung gespeichert ist, und dies nicht tun   Veränderung, auch wenn die Struktur eines   Datenbank zugrunde liegenden ein Datensatz ist   geändert.

Also, seien Sie vorsichtig, wenn Sie später weitere Felder hinzufügen zu einer Tabelle, müssen Sie die neuen Felder der Komponente hinzuzufügen. Das Gleiche gilt für Felder zu löschen.

Wenn Sie wirklich nicht persistente Felder wollen, ist es eine andere Lösung. An jedem Gitter oder Steuerelement, das das berechnete Feld zeigen soll, können Sie benutzerdefinierte es zeichnen. Zum Beispiel haben viele Grid Controls ein OnCustomDraw Ereignis. Sie können dort Ihre Berechnung tun.

Wenn Sie haben, zu wissen, zur Laufzeit berechneten Felder Namen zu sein, können Sie so etwas verwenden.

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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top