FireDAC VCL Komponente: Datenquelle zur Laufzeit erstellen

Einleitung

Um der FireDAC VCL Komponente von List & Label im Embarcadero RAD Studio eine Datenquelle zuzuweisen, verwendet man in der Regel den dafür integrierten Dialog für die Eigenschaft DataController > DetailSources der List & Label Komponente:

Entscheidend hierbei ist, dass die Datenquelle bereits zur Design-Zeit, also bereits beim Erstellen der Anwendung, bekannt und konfiguriert sein muss. Doch wie funktioniert das Ganze nun dynamisch zur Laufzeit, sodass man nicht zur Design-Zeit der Anwendung den Dialog verwenden muss, um so bspw. den späteren Anwendern der Anwendung ein Maß an Flexibilität zu ermöglichen? Genau diesen Aspekt zeigen wir im Folgenden in vereinfachter Form.

Datenquelle dynamisch im Laufzeit-Code

Hierzu verwenden wir zwei TDataSource-Objekte, die die beiden einfachen Tabellen Kunden (Customers) und Bestellungen (Orders) abbilden sollen. Zusätzlich wird später eine relationale Struktur zwischen diesen beiden Tabellen definiert, um eine Master-Detail-Beziehung abzubilden.

Kunden und Bestellungen definieren und mit Daten füllen

Mit Hilfe von TDataSource-Objekten wird die Datenstruktur definiert und gleichzeitig mit Daten gefüllt:

procedure GetDataSource(var DataSourceCustomers, DataSourceOrders: TDataSource);
var

  DataSetCutomers: TClientDataSet;
  DataSetOrders: TClientDataSet;

begin

  {* Create DataSet/DataSource for "Customers" with Data *}
  DataSetCutomers := TClientDataSet.Create(nil);
  with DataSetCutomers do
  begin

    Name := 'Customers';
    FieldDefs.Add('Id', ftInteger);
    FieldDefs.Add('Name', ftString, 255);
    CreateDataSet;

    IndexDefs.Add('PK_Test', 'Id', [ixPrimary, ixUnique]);

    Append;
    FieldByName('Id').AsInteger := 1;
    FieldByName('Name').AsString := 'Lars';

    Append;
    FieldByName('Id').AsInteger := 2;
    FieldByName('Name').AsString := 'Dirk';

    Append;
    FieldByName('Id').AsInteger := 3;
    FieldByName('Name').AsString := 'Torsten';

    Post;

  end;

  DataSourceCustomers := TDataSource.Create(nil);
  DataSourceCustomers.DataSet := DataSetCutomers;

  {* Create DataSet/DataSource for "Orders" with Data and
  define its relation to "Customers" *}
  DataSetOrders := TClientDataSet.Create(nil);
  with DataSetOrders do
  begin

    Name := 'Orders';
    FieldDefs.Add('Id', ftInteger);
    FieldDefs.Add('CustomerID', ftInteger);
    FieldDefs.Add('Amount', ftFloat);
    CreateDataSet;

    IndexDefs.Add('PK_InnerTable', 'Id', [ixPrimary, ixUnique]);
    IndexFieldNames := 'CustomerID';

    Append;
    FieldByName('Id').AsInteger := 1;
    FieldByName('CustomerID').AsInteger := 1;
    FieldByName('Amount').AsFloat := 99.25;

    Append;
    FieldByName('Id').AsInteger := 2;
    FieldByName('CustomerID').AsInteger := 1;
    FieldByName('Amount').AsFloat := 125.99;

    Append;
    FieldByName('Id').AsInteger := 3;
    FieldByName('CustomerID').AsInteger := 2;
    FieldByName('Amount').AsFloat := 12.98;

    Post;

  end;

  DataSourceOrders := TDataSource.Create(nil);
  DataSourceOrders.DataSet := DataSetOrders;

  DataSetOrders.MasterSource := DataSourceCustomers;
  DataSetOrders.MasterFields := 'Id';

end;

Erstellte Datenquelle dem List & Label Objekt zuweisen

Sobald die Strukur mit den Daten erstellt wurde, kann sie dem List & Label Objekt zugewiesen werden:

  {* Create the List & Label object and assign the DataSource *}
  LL := TListLabel25.Create(self);
  GetDataSource(DataSourceCustomers, DataSourceOrders);
  LL.DataController.DataSource := DataSourceCustomers;

Relation in der Datenquelle definieren

Anschließend muss die Relation im DataController definiert werden, die dann von List & Label im Designer und beim Druck verwendet werden soll:

  {* Prepare the relational structure between the DataSources within
  the List & Label DataController *}
  with LL.DataController.DetailSources.Add do
  begin

    Name := 'Customers';
    DataSource := DataSourceCustomers;
    PrimaryKeyField := 'Id';

    with TDetailSourceItem(AddChildNode) do
    begin

      Name := 'Orders';
      DataSource := DataSourceOrders;
      MasterKeyField := 'Id';
      DetailKeyField := 'CustomerID';

    end;

  end;

Designer starten und Datenquellen überprüfen

Nun kann einfach die Design-Funktion aufgerufen werden, um das Ergebnis der bereitgestellten Datenquellen zu überprüfen und den Bericht zu erstellen:

  // Start the Designer
  LL.Design();

grafik

Fazit

Somit ist es schnell und einfach möglich dem späteren Anwender der Applikation einen recht flexiblen Ansatz der Datengestaltung beim Reporting zu ermöglichen.