我需要避免尝试更新连接到TSQLQuery的Delphi TClientDataset中的非物理字段 [英] I need to avoid attempting to update non-physical fields in a Delphi TClientDataset connected to a TSQLQuery

查看:343
本文介绍了我需要避免尝试更新连接到TSQLQuery的Delphi TClientDataset中的非物理字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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 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 标记在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆