ali ahmadi
ali ahmadi

Reputation: 189

How to create a look up field in TFdMemTable at run time

I'm trying to create a new field in TFDMemTable at run time, the field must be a Combobox and i would like to look up the items for the Combobox from a second TFDMemTable.
How can i achieve this ?
Here is a sample of what i need, i have a main table and a secondary table, i am trying to have a field in the main table with items from the secondary table.
I tried doing something like this :

//First i try creating the second table with the values for the combobox
FDMemTableQualityLiterals.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTableQualityLiterals.FieldDefs.Add('IdValue', ftString, 20, false);
FDMemTableQualityLiterals.CreateDataSet;

FDMemTableQualityLiterals.Open;
FDMemTableQualityLiterals.AppendRecord([1, '480p']);
FDMemTableQualityLiterals.AppendRecord([2, '720p']);
FDMemTableQualityLiterals.AppendRecord([3, '1080p']);


// then i try to create the main table with a few field including the qualityID field
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('Name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
FDMemTable1.Close;
//i try to link/create a new field like qualityID that has literal values instead of an id
CreateLookupField(TDataset(FDMemTable1), 'QualityLookup', TDataset(FDMemTableQualityLiterals), 'QualityID', 'QualityID', 'IdValue');
FDMemTable1.CreateDataSet;

FDMemTable1.open;
FDMemTable1.AppendRecord([0, 'item1', 1]);
FDMemTable1.AppendRecord([1, 'item2', 2]);
FDMemTable1.AppendRecord([2, 'item3', 3]);
// i use this code to show the result in devExpress
cxGrid1DBTableView1.DataController.DataSource := DataSource1;
cxGrid1DBTableView1.DataController.CreateAllItems();


Procedure TForm1.CreateLookupField( ATable: TDataSet; AFieldName: String; ALookupDataset: TDataset; AKeyfields: String; ALookupKeyfields: String; ALookupResultField : String);
Var
  I : Integer;
  NewField : TField;
Begin
  with ATable do begin
    if FieldDefs.Updated = False then
      FieldDefs.Update;
    If FindField(AFieldName) = Nil then
    begin
      NewField := TStringField.Create(ATable);
      NewField.FieldName := AFieldName;
      NewField.KeyFields := AKeyFields;
      NewFIeld.LookupDataSet := ALookupDataset;
      NewField.LookupKeyFields := ALookupKeyFields;
      NewField.LookupResultField := ALookupResultField;
      NewField.FieldKind := fkLookup;
      NewField.Dataset := ATable;
    end;
  end;
End;

But it doesn't work and i get an error saying the qualityID doesn't exist, even if we exclude the error, is this approach correct ? is this the way to do this?

Upvotes: 2

Views: 3288

Answers (1)

M.mhr
M.mhr

Reputation: 1749

TFieldDefs is a list of Field Definitions not a list of Fields, CreateDataSet method creates the fields list from TFieldDefs but when you close the DataSet, Fields list will be cleared.

For creating the LoockUp Fields the dataset must be closed and a closed dataset has an empty field list but you need to the fields when you are creating the lookup fields !. So you should create your field list manually for a closed dataset, do it like this :

var
 I : Integer;
begin
  FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
  FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
  FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);

  FDMemTable1.CreateDataSet; //This is unnecessary
  FDMemTable1.Close;

  for I := 0 to FDMemTable1.FieldDefs.Count - 1 do
   begin
    if FDMemTable1.FindField(FDMemTable1.FieldDefs[i].Name) = Nil then
     FDMemTable1.FieldDefs.Items[i].CreateField(FDMemTable1);
   end;

  CreateLookupField(TDataset(FDMemTable1), 'QualityLookup', TDataset(FDMemTableQualityLiterals), 'QualityID', 'QualityID', 'IdValue');
  FDMemTable1.CreateDataSet;



  //FDMemTable1.open; //not need to `FDMemTable1.open` after `FDMemTable1.CreateDataSet`, `CreateDataSet` method sets Active = True 
  FDMemTable1.AppendRecord([0, 'Ali', 1]);
  FDMemTable1.AppendRecord([1, 'Ali2', 2]);
  FDMemTable1.AppendRecord([2, 'Ali3', 3]);
  //FDMemTable1.AppendRecord([1, 'Ali', 1, 1]);
  //FDMemTable1.AppendRecord([1, 'Ali']);
  //FDMemTable1.Close;

//  FDMemTable1.CreateDataSet;
//  cxGrid1DBTableView1.DataController.DataSource := DataSource1;

  //FDMemTable1.Active := true;
//  cxGrid1DBTableView1.DataController.CreateAllItems();
end;

Upvotes: 4

Related Questions