Database 如何在运行时更改Clientdataset字段数据类型

Database 如何在运行时更改Clientdataset字段数据类型,database,delphi,dataset,tclientdataset,Database,Delphi,Dataset,Tclientdataset,对于在设计时定义了字段的Delphi ClientDataSet,在运行时是否有方法更改特定字段的数据类型(更改cds.fields[n].datatype) 我有一个传统的Delphi7程序,在设计时设置了SQLDataSet和ClientDataSet字段(以覆盖各种属性) 它们连接到第三方Sybase SQL Anywhere 11数据库 最近,供应商将所有“描述”字段从VarChar(128)更改为long VarChar,但仅针对某些客户。因此,当我查询这些“描述”字段时,我的代码必须

对于在设计时定义了字段的Delphi ClientDataSet,在运行时是否有方法更改特定字段的数据类型(更改cds.fields[n].datatype)

我有一个传统的Delphi7程序,在设计时设置了SQLDataSet和ClientDataSet字段(以覆盖各种属性)

它们连接到第三方Sybase SQL Anywhere 11数据库

最近,供应商将所有“描述”字段从VarChar(128)更改为long VarChar,但仅针对某些客户。因此,当我查询这些“描述”字段时,我的代码必须支持这两种类型的字段

我希望在类字段类型上设置条件编译(然后在打开SQL/客户机数据集之前添加字段),但是编译器忽略了类的组件定义部分中的{$IFDEF}条件(我越想,这就越有意义)


有几十个模块,数百个字段受到影响,因此任何见解都值得赞赏。

我以前也遇到过这个问题,不是CD,而是设计时使用持久字段的TADODataSet。我认为下面的代码将帮助您了解如何修复/修补CD数据集

其思想是查询相关的表模式;获取实际的fileds数据类型;以及通过从数据集中取消附加持久字段并添加新的匹配持久字段来“更改”持久字段类型:

// TData class    
procedure TData.DataModuleCreate(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to ComponentCount - 1 do
    if (Components[I] is TCustomADODataSet) then
      DataSetPrepareMemoFields(TDataSet(Components[I]));
end;

procedure TData.DataSetPrepareMemoFields(DataSet: TDataSet);
var
  Fld: TField;
  I: Integer;
  FldName, CompName: string;
  AOwner: TComponent;
begin
  // Here you need to query the actual table schema from the database 
  // e.g. ADOConnection.GetFieldNames and act accordingly

  // check which DataSet you need to change
  // if (DataSet = dsOrders) or ... then... 

  if DataSet.FieldList.Count > 0 then
    for I := DataSet.FieldList.Count - 1 downto 0 do 
    begin
      if DataSet.FieldList.Fields[I].ClassNameIs('TMemoField') and (DataSet.FieldList.Fields[I].FieldKind = fkData) then 
      begin
        // save TMemoField properties
        AOwner := DataSet.FieldList[I].Owner;
        CompName := DataSet.FieldList[I].Name;
        FldName := DataSet.FieldList.Fields[I].FieldName;
        // dispose of TMemoField
        DataSet.FieldList[I].DataSet := nil; // Un-Attach it from the DataSet
        // create TWideADOMemoField instead
        Fld := TWideADOMemoField.Create(AOwner); // Create new persistent Filed instead 
        Fld.Name := CompName + '_W';
        Fld.FieldName := FldName;
        Fld.DataSet := DataSet;
      end;
    end;
end;
也就是说,在我解决了这个问题之后,我再也没有使用过持久字段。
我的所有字段都是在运行时生成的。包括计算/查找/内部字段。

要么在运行时之前根本不添加该字段,然后在该点添加适当的类型,要么在运行时删除它(如果需要),然后重新添加所需类型的新字段。@KenWhite说了什么。它应该可以正常工作,但如果有问题的字段具有对应的FieldDef,则需要删除并重新创建该字段,否则在打开CD时,可能会出现错误,抱怨FieldDef中定义的数据类型与替换的TField之间不匹配。就我个人而言,我倾向于重新创建所有字段/fielddef,而不仅仅是涉及的字段。不幸的是,数据库的更改比我最初想象的要多——这可能涉及1000个字段(跨多个项目)。它也有副作用——我广泛使用DBgrids——我得到的是(备忘录)而不是数据。我可以设置字段的OnGetText-但同样,有很多字段。。。CDS是在设计时定义的,但是我动态地创建了SQL——我正在考虑在SQL中对VARCHAR进行强制转换/转换。嗯,字段[n]可能有问题。数据大小例如-将一个长varchar强制转换到CD中最初定义为varchar[128]的字段中…@MartynA-我从SDS和CD中删除了该字段。然后使用条件编译1)将适当的字段/类型添加到公共声明中;2)添加SDS字段定义;和,3)添加CDS字段DEF和字段。工作很好,但当然,现在网格中有一个“备忘录”。我有一种感觉,我会“分叉”代码…“分叉地狱”,我想你可能会说(对不起,无法抗拒)。说真的,我想得越多,我就越倾向于避免任何持久性字段/字段定义:要么在代码中创建它们,要么让CDS通过SDS从服务器获得的内容来创建它们。我已经完成了转换,但这看起来很有趣。我可以看到问题,因为我通过自动声明引用了字段——例如在datamodule类声明中,我有myStringField:TStringField;如果我像上面那样替换数据类型,我想我可能仍然会看到不兼容的类型错误。我需要一周左右的时间才能回到这个话题上。现在-谢谢!我正在尝试这种技术,但它不允许我在数据集打开时添加字段,也不允许我在数据集关闭时访问字段