Home › Forums › kbmMemTable › Add Calculation Fields Runtime in BeforeOpen
- This topic has 2 replies, 2 voices, and was last updated 6 years, 1 month ago by
Theprasit.
-
AuthorPosts
-
-
January 31, 2020 at 06:13 #54414
Theprasit
ParticipantJust 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; -
February 1, 2020 at 22:39 #54417
kimbomadsen
KeymasterHi,
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
-
February 2, 2020 at 09:33 #54419
Theprasit
ParticipantHi,
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;
-
-
AuthorPosts
- You must be logged in to reply to this topic.
