内容提要:我的代码试图更新在一个Delphi XE非物理字段TClientDataset
,(连接到TSQLQuery
其SQL
属性集)被创建作为运行时的结果Open
命令。
我有一个TClientDataset
连接到TDatasetProvider
连接到TSQLQuery
连接到TSQLConnection
。 这些对象的前3被封装在一个库中的几个类,我在很多地方使用了几个项目中。 这些类在运行时创建这些3个对象,消除重复代码显著量,必要的,因为我有很多很多的这些三胞胎。
非常典型地我将加载TClientDataset
从数据库中指定的一些SQL SQL
的财产TSQLQuery
,并呼吁Open
上TClientDataSet
。 该Fields
中TClientDataset
通过此调用创建Open
即。 他们不事先存在Open
。
我所遇到的状况下三个生成的进入领域的问题TClientDataset
是非物质; 也就是说,SQL的功能计算生成它们。 不幸的是,在TClientDataset
,这3个领域没有得到任何创建不同的物理场; 他们FieldKind
是fkData
(理想情况下是fkInternalCalc
), Calculated
属性为False
(理想情况下是True
)和他们的ProviderFlags
包括pfInUpdate
(在理想情况下不应该)。 毫不奇怪,当谈到时间做一个ApplyUpdates
上TClientDataset
抛出一个异常...
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
在国旗TDatasetProvider
的OnUpdateData
事件处理程序。 然而,这种解决方案要求的特定字段名称是已知的这个功能,其位于在上面提到的一般类,从而打破了代码的通用性。
我所寻找的是这些信号领域的事件处理函数的计算性质的通用手段。
我不能改变他们的FieldKind
或Calculated
性能(以fkInternalCalc
和True
的分别后) Open
电话,因为这产生WorkCDS: Cannot perform this operation on an open dataset
异常消息。 而且,我无法改变前这些属性Open
,因为这种呼叫Fields
还不存在。
我可以删除pfInUpdate
从这些标志Field
的ProviderFlags
后的属性Open
,但这没有得到传递到‘三角洲’ TClientDatset
即到达OnUpdateData
事件处理程序。 我也尝试设置字段的FieldDefs.InternalCalcField
性能; 这同样没有得到传递给三角洲数据集。
因此,所有我已经试过信令的想法都没有奏效。 我会是什么新的想法或一种替代方法感激。
所有这一切我所遇到的互联网搜索结果 - 包括卡里Jensen的优秀文章 - 处理设计时还是非SQL生成的,并不适用于我的情况设置。
您可以创建在您的类的机制为您希望在更新过程中忽略各个字段预配置的ProviderFlags。
按你的问题的意见,我建议你在类中创建一个新的方法来打开内部的ClientDataSet,所有的魔法会采取这个方法里面的地方。
首先,一个简单的机制是,一个新的TStringList属性,它列出了所有你要忽略的领域,你会被名称相匹配。 你可以随意采用这样或创建一个新的更好的机制,重要的是你能够确定要配置这样的字段。
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;
把它作为一个想法。
我写到这里的所有代码,也许语法是错误的,但它显示了整体思路。
可以通过在CDS设定相应的可选参数传递从客户端ProviderFlags(以及一些其他性质),以提供(增量)侧。 不要忘记设置IncludeInDelta PARAM
文章来源: I need to avoid attempting to update non-physical fields in a Delphi TClientDataset connected to a TSQLQuery