我需要避免尝试更新连接到TSQLQuery的Delphi TClientDataset中的非物理字段 [英] I need to avoid attempting to update non-physical fields in a Delphi TClientDataset connected to a TSQLQuery
问题描述
Precis:我的代码正在尝试更新Delphi XE中的非物理字段 TClientDataset
,(连接到一个 TSQLQuery
其 SQL
属性集)是由运行时打开命令创建的。
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.
我有一个 TClientDataset
连接到 TDatasetProvider
连接到 TSQLQuery
连接到 TSQLConnection
。这些对象中的前3个被封装在一个库中的几个类中,我在多个项目的许多地方使用。这些类在运行时创建这3个对象,并消除了大量的重复代码,因为我有许多这些三元组。
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.
通常我将加载 TClientDataset
通过在 TSQLQuery $ c的
SQL
属性中指定一些SQL $ c>并调用在
。在 TClientDataSet
上打开 TClientDataset
中的字段
通过此调用打开
ie。它们在之前不存在。
。
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
.
我遇到了一个问题,生成到 TClientDataset
中的字段是非物理的;也就是说,SQL会进行计算以生成它们。不幸的是,在 TClientDataset
中,这3个字段与物理字段的创建方式不同;他们的 FieldKind
是 fkData
(理想情况下它将是 fkInternalCalc
) ,计算的
属性是 False
(理想情况下,它将是 True
)和他们的 ProviderFlags
包括 pfInUpdate
(理想情况下不应该)。毫不奇怪,当在 TClientDataset
中执行 ApplyUpdates
时,抛出异常...
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'.
我可以通过清除这些字段的 pfInUpdate $ c $来避免此错误c>标记在
TDatasetProvider
的 OnUpdateData
事件处理程序。然而,这个解决方案要求这个函数的特定字段名称位于上面提到的泛型类中,从而打破了代码的一般性。
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.
我不能更改他们的 FieldKind
或计算的
属性(分别为 fkInternalCalc
和 True
) 打开
调用,因为这会生成一个 WorkCDS:无法在打开的数据集
异常消息上执行此操作。而且,由于 Fields
不存在,所以我不能在 Open
调用之前更改这些属性。
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.
我可以从这些字段中删除
的 pfInUpdate
标志 ProviderFlags
在之后的属性打开
,但这不会传递到Delta TClientDatset
到达 OnUpdateData
事件处理程序。我还尝试设置字段的 FieldDefs.InternalCalcField
属性;再次,这不会传递给Delta数据集。
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.
我遇到的所有互联网搜索结果 - 包括Cary Jensen的优秀文章 - 处理设计时或非SQL生成的安装程序不适用于我的情况。
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.
推荐答案
您可以在课堂中创建一个机制,在更新过程中为您想要忽略的各个字段配置ProviderFlags。
You can create a mechanism in your class to pre-configure the ProviderFlags for the individual fields you want to ignore in your Update process.
根据您的问题的评论,我建议你要在类中创建一个新方法来打开内部的ClientDataSet,所有的魔法都会发生在这个方法之内。
As per the comments on your question, I'm suggesting you to create a new method in the class to open the inner ClientDataSet, all the magic will take place inside this method.
首先,一个简单的机制是包括一个新的TStringList属性列出您要忽略的所有字段,您将按名称匹配。您可以自由地采用这种方式或创建一个更好的机制,重要的是您可以确定要配置哪些字段。
First, one simple mechanism is to include a new TStringList property which lists all the fields you want to ignore, that you will match by name. Feel free to adopt this or create a new better mechanism, the important thing is you're able to identify which fields you want to configure that way.
type
TMyClass = class
// all your current class here
private
FUpdateIgnoredFields: TStringList;
public
property UpdateIgnoredFields: TStringList read FUpdateIgnoredFields write SetUpdateIgnoredFields;
//don't forget to create this in your constructor, free it in the destructor
//and Assign any new value in the SetUpdateIgnoreFields method, as usual.
procedure OpenInnerCDS; //the magic goes here
end;
procedure TMyClass.OpenInnerCDS;
var
FieldName: string;
AFieldToIgnore: TField;
begin
//opens the inner cds, but before that, configures the update-ignored
//fields in the underlying dataset
//Let's call it InnerBaseDataSet;
FInnerBaseDataSet.Open; //this opens the DataSet and creates all the fields for it.
try
for FieldName in FUpdateIgnoredFields do
begin
AFieldToIgnore := FInnerBaseDataSet.FindField(FieldName);
if Assigned(AFieldToIgnore) then
AFieldToIgnore.ProviderFlags := AFieldToIgnore.ProviderFlags - [pfInUpdate, pfInWhere];
end;
//now, let's open the ClientDataSet;
FInnerClientDataSet.Open;
finally
//I suggest no matter what happens, always close the inner data set
//but it depends on how the CDS->Provider->DataSet interaction is configured
FInnerBaseDataSet.Close;
end;
end;
//the way you use this is to replace the current ClientDataSetOpen with something like:
var
MyInsance: TMyClass;
begin
MyInstance := TMyInstance.Create(); //params
try
//configuration code here
//MyInstance.InnerCDS.Open; <-- not directly now
MyInstance.UpdateIgnoreFields.Add('CALCULATED_SALARY');
MyInstance.OpenInnerCDS;
//use the CDS here.
MyInstance.InnerCDS.ApplyUpdates(-1); //safely apply updates now.
finally
MyInstance.Free;
end;
end;
把它当成一个想法。
我在这里写了所有的代码,也许语法错了,但它显示了整个想法。
I wrote all the code here, maybe the syntax is wrong, but it shows the whole idea.
这篇关于我需要避免尝试更新连接到TSQLQuery的Delphi TClientDataset中的非物理字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!