-->

我需要避免试图更新德尔福的TClientdataSet连接到TSQLQuery非物理场(I need

2019-08-03 02:15发布

内容提要:我的代码试图更新在一个Delphi XE非物理字段TClientDataset ,(连接到TSQLQuerySQL属性集)被创建作为运行时的结果Open命令。

我有一个TClientDataset连接到TDatasetProvider连接到TSQLQuery连接到TSQLConnection 。 这些对象的前3被封装在一个库中的几个类,我在很多地方使用了几个项目中。 这些类在运行时创建这些3个对象,消除重复代码显著量,必要的,因为我有很多很多的这些三胞胎。

非常典型地我将加载TClientDataset从数据库中指定的一些SQL SQL的财产TSQLQuery ,并呼吁OpenTClientDataSet 。 该FieldsTClientDataset通过此调用创建Open即。 他们不事先存在Open

我所遇到的状况下三个生成的进入领域的问题TClientDataset是非物质; 也就是说,SQL的功能计算生成它们。 不幸的是,在TClientDataset ,这3个领域没有得到任何创建不同的物理场; 他们FieldKindfkData (理想情况下是fkInternalCalc ), Calculated属性为False (理想情况下是True )和他们的ProviderFlags包括pfInUpdate (在理想情况下不应该)。 毫不奇怪,当谈到时间做一个ApplyUpdatesTClientDataset抛出一个异常...

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在国旗TDatasetProviderOnUpdateData事件处理程序。 然而,这种解决方案要求的特定字段名称是已知的这个功能,其位于在上面提到的一般类,从而打破了代码的通用性。

我所寻找的是这些信号领域的事件处理函数的计算性质的通用手段。

我不能改变他们的FieldKindCalculated性能(以fkInternalCalcTrue的分别后) Open电话,因为这产生WorkCDS: Cannot perform this operation on an open dataset异常消息。 而且,我无法改变前这些属性Open ,因为这种呼叫Fields还不存在。

我可以删除pfInUpdate从这些标志FieldProviderFlags后的属性Open ,但这没有得到传递到‘三角洲’ TClientDatset即到达OnUpdateData事件处理程序。 我也尝试设置字段的FieldDefs.InternalCalcField性能; 这同样没有得到传递给三角洲数据集。

因此,所有我已经试过信令的想法都没有奏效。 我会是什么新的想法或一种替代方法感激。

所有这一切我所遇到的互联网搜索结果 - 包括卡里Jensen的优秀文章 - 处理设计时还是非SQL生成的,并不适用于我的情况设置。

Answer 1:

您可以创建在您的类的机制为您希望在更新过程中忽略各个字段预配置的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;

把它作为一个想法。

我写到这里的所有代码,也许语法是错误的,但它显示了整体思路。



Answer 2:

可以通过在CDS设定相应的可选参数传递从客户端ProviderFlags(以及一些其他性质),以提供(增量)侧。 不要忘记设置IncludeInDelta PARAM



文章来源: I need to avoid attempting to update non-physical fields in a Delphi TClientDataset connected to a TSQLQuery