Database Delphi-在运行时将字段更改为计算字段。这是一种好的做法吗?

Database Delphi-在运行时将字段更改为计算字段。这是一种好的做法吗?,database,delphi,calculated-field,tdataset,Database,Delphi,Calculated Field,Tdataset,正如问题的标题一样,我与一位同事就如何使用计算字段进行了争论。 据我所知,计算字段是在运行时创建的,就像弗朗索瓦在这个问题上所说的那样。关于同一个问题,还有另一个来自sabri.arslan的问题,建议将现有字段更改为计算字段(代码如下) 我认为,此更改会导致指定TField的未知行为。在运行时将数据集字段更改为计算字段是否安全?这会产生什么样的问题 乐:这是一个问题。其目的是演示在运行时在数据集上添加计算字段的良好实践。而且,是的,在运行时添加计算字段是糟糕的设计 LE2:这只是“不要这样做”

正如问题的标题一样,我与一位同事就如何使用计算字段进行了争论。 据我所知,计算字段是在运行时创建的,就像弗朗索瓦在这个问题上所说的那样。关于同一个问题,还有另一个来自sabri.arslan的问题,建议将现有字段更改为计算字段(代码如下)

我认为,此更改会导致指定TField的未知行为。在运行时将数据集字段更改为计算字段是否安全?这会产生什么样的问题

乐:这是一个问题。其目的是演示在运行时在数据集上添加计算字段的良好实践。而且,是的,在运行时添加计算字段是糟糕的设计


LE2:这只是“不要这样做”的一个例子。作为一个论点,我问在这样做之后,讨论中的领域的行为是什么。该字段将如何工作?

一个TField要么映射到数据库列,要么不映射到数据库列,并通过计算得到。这应该在设计时设置。在运行时改变这一点的任何尝试在我看来都是糟糕的设计,而且你正在为自己设置许多潜在的麻烦

不,这不是一个好的做法。代码复杂这一简单事实表明,应该避免这种做法。有人已经提到了接吻原则,我同意这一点

特别是,数据集必须打开两次这一简单事实足以让我讨厌这种做法

此外,将字段的性质从data更改为computed将改变数据集在其内部记录表示中组织字段的方式(数据集称之为记录缓冲区)。这种表示形式在不同的数据集实现之间可能有很大的不同。由于问题没有确定特定的数据集,行为的变化(一般而言):

  • 数据字段将其值存储在属于底层数据库客户端的结构中;计算字段将其值存储在非持久缓冲区中
  • 在数据集打开期间,有一个名为字段绑定的过程,该过程包括将数据字段绑定到数据库客户端对应的结构;当绑定失败时,数据集通常会引发异常;计算的字段不参与此过程,因为它们使用内部字段缓冲区存储其值
  • 该字段在成为计算字段后,将以我们习惯的方式在执行OnCalcFields事件期间接受值;它可能不用于过滤目的,具体取决于数据集实现

  • 然而,我的某个数据集实现会带来一些其他后果,这取决于它的用途和特性。

    有人注意到这段代码吗

    procedure TSampleForm.btnOpenClick(Sender: TObject);
    begin
     if dsSample.Active then
       dsSample.Close;
     dsSample.SQL.text:='select id,state,oldstate,"" as txtState,"" as txtOldState from states where active=1';
     dsSample.Open;
    end;
    
    他没有将数据库字段更改为计算字段…他将不存在的字段更改为计算字段。他知道字段类型…它将是一个字符串…所以这是一个大问题…不…这是一个黑客…是的…你可以用Cast在SQL中做同样的事情…事实上,我从来没有真正看到使用计算字段的理由…我通常可以在SQL中做同样的事情更容易

    我添加了更多的信息后,多一点挖掘为什么不这样做

    sabri.arslan代码…从字段列表创建字段…还存在设置键缺失和处理继承字段等问题

    dmp:=DataSet.FieldDefs.Items[i].FieldClass.Create(self);
    
    然后我们有弗朗索瓦

    if you call the none hacked code you get this...
      for I := 0 to MyQuery.FieldDefList.Count - 1 do
        with MyQuery.FieldDefList[I] do
          if (DataType <> ftUnknown) and not (DataType in ObjectFieldTypes) and
            not ((faHiddenCol in Attributes) and not MyQuery.FIeldDefs.HiddenFields) then
            CreateField(Self, nil, MyQuery.FieldDefList.Strings[I]);
    
    如果你调用无黑客代码,你会得到这个。。。
    对于I:=0到MyQuery.FieldDefList.Count-1 do
    使用MyQuery.FieldDefList[I]do
    if(数据类型ftUnknown)和not(ObjectFieldTypes中的数据类型)和
    而不是((属性中的faHiddenCol)和MyQuery.FIeldDefs.HiddenFields)
    CreateField(Self、nil、MyQuery.FieldDefList.Strings[I]);
    
    嗯…缺少SetKeyFields会导致不可预见的行为吗?此外,如果您的ObjectView属性设置为True…您的数据集对于分层字段将无法正常运行…看起来更安全 只是调用黑客来创建字段,而不是使用他的代码…除此之外,您必须确定您的数据集组件从未调用此代码

    CreateField调用CreateFieldComponent,您得到的结果是:=FieldClassType.Create(所有者)为您的TField

    摘自TFieldDef的Borland帮助 字段定义有相应的TField对象,但并非所有TField对象都有相应的字段定义。例如,计算字段没有字段定义对象

    所以我问你…你是否肯定你没有通过动态创建CalculatedField来引入未知行为? 您确定这些字段尚未创建还是以后不会创建?(sabri.arslan代码中有一个bug,因为他执行打开/打开后操作…他正在覆盖原始的TField…,我不明白为什么我们需要为已经打开的数据集重新创建TField)

    那么,当数据集调用CreateFields时会发生什么情况(BDE和ADO在InternalOpen上执行此操作) 并检查以确保字段中没有值…所有数据集组件都这样做吗 怎么办?他们不必)。 您已经创建的字段会发生什么情况…它们会被覆盖吗?我没有看到任何代码 在TDataset或TFieldDef中,检查是否已为除
    检查DefaultFields(如果字段有值)。

    这个答案中没有比问题本身更重要的内容。-“在运行时将数据集字段更改为计算字段安全吗?”——“我不这么认为。”如果问题中出现的复杂代码没有具体原因,请遵循KISS原则:设计计算字段,在运行时填充它们。即使在那些情况下
    if you call the none hacked code you get this...
      for I := 0 to MyQuery.FieldDefList.Count - 1 do
        with MyQuery.FieldDefList[I] do
          if (DataType <> ftUnknown) and not (DataType in ObjectFieldTypes) and
            not ((faHiddenCol in Attributes) and not MyQuery.FIeldDefs.HiddenFields) then
            CreateField(Self, nil, MyQuery.FieldDefList.Strings[I]);