Precis: My code is attempting to update non-physical fields in a Delphi XE TClientDataset
, (connected to a TSQLQuery
with its SQL
property set) that were created as result of a runtime Open
command.
I have a TClientDataset
connected to a TDatasetProvider
connected to a TSQLQuery
connected to a TSQLConnection
. The first 3 of these objects are encapsulated within a couple of classes in a library that I use in many places on several projects. These classes create these 3 objects at runtime and eliminate a significant amount of repetitious code, necessary as I have many, many of these triplets.
Quite typically I will load the TClientDataset
from a database by specifying some SQL in the SQL
property of the TSQLQuery
and calling Open
on the TClientDataSet
. The Fields
in the TClientDataset
are created via this call to Open
ie. they don't exist prior to Open
.
I have run into a problem in a situation where three of the fields generated into the TClientDataset
are non-physical; that is, the SQL does calculations to generate them. Unfortunately, in the TClientDataset
, these 3 fields do not get created any differently to the physical fields; their FieldKind
is fkData
(ideally it would be fkInternalCalc
), Calculated
property is False
(ideally it would be True
) and their ProviderFlags
include pfInUpdate
(which ideally it should not). Not surprisingly, when it comes time to do an ApplyUpdates
on the TClientDataset
an exception is thrown...
Project XXX.exe raised exception class TDBXError with message
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'Received'.
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'Issued'.
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'DisplayTime'.
I can avoid this error by clearing these field's pfInUpdate
flags in the TDatasetProvider
's OnUpdateData
event handler. However this solution requires that the specific field names be known to this function which sits in the generic classes mentioned above, thus breaking the code's generality.
What I am looking for is a generic means of signalling the calculated nature of these fields to the event handler function.
I cannot change their FieldKind
or Calculated
properties (to fkInternalCalc
and True
respectively) after the Open
call as this generates a WorkCDS: Cannot perform this operation on an open dataset
exception message. And, I cannot change these properties before the Open
call since the Fields
do not exist yet.
I can remove the pfInUpdate
flag from these Field
's ProviderFlags
properties after Open
but this does not get passed onto the "Delta" TClientDatset
that arrives at the OnUpdateData
event handler. I also tried setting the field's FieldDefs.InternalCalcField
properties; again this does not get passed to the Delta dataset.
So, all the signalling ideas that I have tried have not worked. I would be grateful for any new ideas or an alternate approach.
All of the internet search results that I have encountered - including Cary Jensen's excellent articles - deal with design-time or non-SQL generated setups that do not apply to my situation.
Open
the TClientDataSet but rather when theApplyUpdates
occurs. I have coded and successfully tested an alternate approach where I save a pointer to the previousOnUpdateData
event handler (EH) and set a new local EH (whose first task is to call the previous EH). The localOnUpdateData
EH contains some specific code that clearsProviderFlags
for each non-physical field on the "Delta" dataset. – Socinian