【问题标题】:How to get TFDQuery to recognise when new fields are added to a TFDMemTable it is querying via TFDLocalSQL如何让 TFDQuery 识别何时将新字段添加到它通过 TFDLocalSQL 查询的 TFDMemTable
【发布时间】:2017-03-28 00:27:47
【问题描述】:

将字段添加到现有 TFDMemTable 后,任何通过 TFDLocalSQL 查询该表的 TFDQuery 都无法识别新字段。

下面的代码说明了这一点:在代码中添加了一个字段的 TFDMemTable 和在该表上执行选择的 TFDQuery。 (假设将 TFDMemTable 添加到 TFDLocalSQL 的 DataSets 属性并且 TFDQuery 指向 TFDConnection)将字段添加到实时 TFDMemTable 的过程来自example project 和使用 Unprepare,这似乎不起作用在这种情况下,来自这个question

procedure TForm2.FormCreate(Sender: TObject);
begin

  with FDMemTable1.FieldDefs.AddFieldDef do begin
    Name := 'col1';
    DataType := ftString;
    Size := 10;
  end;
  FDMemTable1.CreateDataSet;
  FDMemTable1.Active := true;

  FDQuery1.SQL.Text := 'SELECT * FROM FDMemTable1';

  FDConnection1.Connected := true;
  FDLocalSQL1.Active := true;
  FDQuery1.Active := true;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  tempMT: TFDMemTable;
begin
  tempMT := TFDMemTable.Create(nil);

  try
    tempMT.Data := FDMemTable1.Data;
    FDMemTable1.Close;
    with FDMemTable1.FieldDefs.AddFieldDef do begin
      Name := 'col99';
      DataType := ftString;
      Size := 10;
    end;
    FDMemTable1.Open;
    FDMemTable1.MergeDataSet(tempMT, dmDataSet, mmNone);
    if not FDMemTable1.FieldDefs.Updated then FDMemTable1.FieldDefs.Update;
  finally
    tempMT.Free;

    FDQuery1.Active := false;
    FDQuery1.Unprepare;              // this is meant to uncache the fields
    FDQuery1.Active := true;         // Does not include 'col99' in result set
  end;
end;

该字段肯定已添加到 TFDMemTable 并且可以正常工作。关于如何让 TFDQuery 识别新列的任何提示。

【问题讨论】:

    标签: delphi firedac


    【解决方案1】:

    我认为您出现这种行为的原因是您的代码缺少一个步骤。

    在点击处理程序的finally 子句中,您需要关闭 FDConnection,像这样

      finally
        tempMT.Free;
    
        FDConnection1.Connected := False;
        FDQuery1.Active := false;
        FDQuery1.Unprepare;              // this is meant to uncache the fields
        FDQuery1.Active := true;         // Does include 'col99' in result set
        Caption := IntToStr(FDQuery1.FieldCount);
      end;
      PageControl1.ActivePage := TabSheet3;  // has FDQuery grid
    

    完成上述更改后,您应该会发现您在 FDQuery1 中获得了添加的列。顺便说一句,你可以取出FDQuery.Unprepare,因为它没有区别。 Prepare 通常用于编译后端数据库服务器内部查询的 SQL 代码。在这种情况下,不涉及后端服务器,因为 FDLocalSQL1 组件从 mem 表中为 FDQuery1 生成数据。 Unprepare 通常会告诉后端服务器可以释放编译好的查询资源。

    我认为您的版本不起作用的原因是因为调用 GetActualActive

    procedure TFDCustomLocalSQL.CheckActivate;
    var
      i: Integer;
    begin
      if GetActualActive and not FActivated then begin
        for i := 0 to DataSets.Count - 1 do
          DataSets.CheckUnique(DataSets[i]);
        FActivated := True;
        InternalAttachToSQL;
        for i := 0 to DataSets.Count - 1 do
          if DataSets[i].IsValid then
            InternalDataSetAdded(DataSets[i]);
      end;
    end;
    

    GetActualActive 定义为

    function TFDCustomLocalSQL.GetActualActive: Boolean;
    begin
      Result := Active and (Connection <> nil) and Connection.Connected;
    end;
    

    所以如果 FDLocalSQL1 之前是活动的,那么 CheckActivate 的其余部分将被跳过,它是,并且 FDConnection 已经连接,它是。因此,断开 FDConnection 允许 CheckActivate 的内部执行,因此 FDLocalSQL1 “注意到​​” FDMemTable1 结构的变化。

    顺便说一句,与其从头开始编写代码,我的项目基于这个:

    D:\D10\Samples\Object Pascal\Database\FireDAC\Samples\Comp Layer\TFDLocalSQL\InMemDB

    这避免了对项目设置方式的一定程度的猜测。

    【讨论】:

    • 谢谢。虽然我不明白为什么,但这很有效。我之前曾尝试断开并重新连接无效的 TFDConnection。此外,我以不同的方式阅读了 CheckActivate 源 - TFDLocalSQL 无法激活 除非 TFDConnection 已激活,这符合推荐的激活顺序。再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多