Add Calculation Fields Runtime in BeforeOpen

Home Forums kbmMemTable Add Calculation Fields Runtime in BeforeOpen

Viewing 2 reply threads
  • Author
    Posts
    • #54414
      Theprasit
      Participant

      Just tried to add calculation field runtime using kbmmemtable.BeforeOpen events.

      If using LoadFromDataSet(), everythings are fine.

      If using LoadFromStream(), I got error said “cannot … when dataset is close”.

      What different among 2 methods, and how to acheive by using LoadFromStream().

      My code:-

      procedure TBizDataObject.PrepareCalcFields;
      const
      SUPPORT_FIELD_TYPE: TArray<string>= [
      ‘Txt’, ‘Int’, ‘I64’, ‘Cur’, ‘Dtm’, ‘MEM’
      ];
      var
      sa: TStringDynArray;
      fl: TField;
      begin
      if Length(FUseCalcFields) = 0 then Exit;

      FieldDefs.Update;
      for var ix:= 0 to FieldDefs.Count- 1 do
      FieldDefs[ix].CreateField(Self);

      fl:= nil;
      for var ix:= 0 to High(FUseCalcFields) do
      begin
      if ix <= FCalcFields.Count- 1 then
      begin
      sa:= SplitString(FCalcFields.ValueFromIndex[ix], ‘\’);
      case IndexText(sa[0], SUPPORT_FIELD_TYPE) of
      0: begin
      fl:= TStringField.Create(Self);
      (fl as TStringField).Size:= StrToIntDef(sa[1], 10);
      end;
      1: fl:= TIntegerField.Create(Self);
      2: fl:= TLargeintField.Create(Self);
      3: fl:= TCurrencyField.Create(Self);
      4: fl:= TDateTimeField.Create(Self);
      5: fl:= TMemoField.Create(Self);
      end;
      fl.FieldName:= FCalcFields.Names[ix];
      fl.FieldKind:= fkCalculated;
      fl.DataSet:= Self;
      end;
      end;
      // Reset to default
      FUseCalcFields:= [];
      end;

       

    • #54417
      kimbomadsen
      Keymaster

      Hi,

      I assume you compare LoadFromDataset where you do not include mtcpoStructure as option?

      If you predefine the memtable with the fields you want it to contain, and use LoadFromStream with the streamformatters sfDef not including sfLoadDef, then it will attempt to map up fields in data with predefined fields, why you would get the effect you are asking for.

       

      best regards

      Kim/C4D

    • #54419
      Theprasit
      Participant

      Hi,

      just sent you a testing code that result in an error.
      This is a N-Tier application that prepare data on server side and transfer as stream over network to client side.
      On client side I used kbmMemTable to load data from stream as use as working table then send update data back to server.

      If you run Button1Click, it’s result in error “mt1: cannot perform this operation on closed dataset”.
      If you run Button2Click, it’s just fined, a calculation field is created as expect.

      I use almost default properties of kbmMemTable and related class (default after create).
      Do I miss anything to fine tune?

      Regards,

      procedure TForm5.Button1Click(Sender: TObject);
      var
      mt_fmt: TkbmBinaryStreamFormat;
      ms: TMemoryStream;
      begin
      mt_fmt:= TkbmBinaryStreamFormat.Create(nil);
      ms:= TMemoryStream.Create;
      try
      // ut is a TUniDacTable which load data from DataBase
      // this part is done on server side and sent a stream over network
      mt2.LoadFromDataSet(ut, [mtcpoStructure]);
      mt2.SaveToStreamViaFormat(ms, mt_fmt);
      ms.Position:= 0;
      
      // this is on client side which get a stream and load back to kbmMemTable
      // mt_fmt on server and client used same properties (default after create)
      mt1.LoadFromStreamViaFormat(ms, mt_fmt);
      
      finally
      mt_fmt.Free;
      ms.Free;
      end;
      dsMem.DataSet:= mt1;
      
      // *** this method got error "mt1: Canoot perform this operation on closed dataset"
      end;
      
      procedure TForm5.Button2Click(Sender: TObject);
      var
      mt_fmt: TkbmBinaryStreamFormat;
      ms: TMemoryStream;
      begin
      mt_fmt:= TkbmBinaryStreamFormat.Create(nil);
      ms:= TMemoryStream.Create;
      try
      // ut is a TUniDacTable which load data from DataBase
      // this part is done on server side and sent a stream over network
      mt2.LoadFromDataSet(ut, [mtcpoStructure]);
      mt2.SaveToStreamViaFormat(ms, mt_fmt);
      ms.Position:= 0;
      
      // this is on client side which get a stream and load back to kbmMemTable
      // mt_fmt on server and client used same properties (default after create)
      mt3.LoadFromStreamViaFormat(ms, mt_fmt);
      
      // mt3 is a temporary kbmMemTable use as my work around solution
      mt1.LoadFromDataSet(mt3, [mtcpoStructure]);
      
      // *** this method run without error, a calculation field is created as expect
      finally
      mt_fmt.Free;
      ms.Free;
      end;
      dsMem.DataSet:= mt1;
      end;
      
      procedure TForm5.mt1BeforeOpen(DataSet: TDataSet);
      var
      fl: TField;
      begin
      mt1.FieldDefs.Update;
      for var ix:= 0 to mt1.FieldDefs.Count- 1 do
      mt1.FieldDefs[ix].CreateField(mt1);
      
      fl:= TStringField.Create(mt1);
      fl.FieldName:= 'Calc';
      fl.FieldKind:= fkCalculated;
      fl.DataSet:= mt1;
      end;
Viewing 2 reply threads
  • You must be logged in to reply to this topic.