繁体   English   中英

有没有办法让 Delphi 的 FireDAC 识别 FireDAC 生成的 PostgreSQL 位置参数?

[英]Is there a way to make Delphi's FireDAC recognize PostgreSQL positional parameters that FireDAC generated?

我正在使用本机 FireDAC Postgres 驱动程序从 FireDAC 到 PostgreSQL 11 执行带有命名参数的查询。 在准备语句期间,FireDAC 将命名参数转换为位置参数,这是正确的。 但是,如果我随后尝试为这些参数赋值,FireDAC 会抛出“参数超出范围”异常。 FireDAC 似乎无法识别它生成的位置参数。 例如,如果原始 SQL 文本如下所示:

SELECT * FROM account WHERE accountid = :accid;

在调用 FDQuery 的 Prepare 方法后,FireDAC 将此查询转换为:

SELECT * FROM account WHERE accountid = $1;

但是当我尝试将值分配给参数时,出现错误。 任务看起来像这样:

FDQuery1.Params[0].AsString = strID;

其中 strID 是一个字符串值,而 accountid 是一个文本字段。 此外,如果我使用类似下面的内容,它会返回 0。

ShowMessage( IntToStr( FDQuery1.Params.Count ) );

我已经大大简化了这段代码,但问题是一样的。 如何让 FireDAC 识别它生成的位置参数?


更新:正如我所提到的,上面的代码大大简化了。 实际发生的是,在我们的框架中,我们有一组例程将值分配给 FireDAC 宏,然后我们通过准备查询并读取 FDQuery 的 Text 属性来生成 SQL 语句。 然后该 SQL 语句被分配给另一个 FDQuery(也是动态创建的)的 SQL.Text 属性,并且在那里查询失败。 因此,这里有一个非常简单的示例,说明代码内部发生的情况:

var
  Query: TFDQuery;
begin
  Query := TFDQuery.Create( nil );
  Query.Connection := PGConnection;
  // In reality, the SQL statement below was generated earlier,
  // from a function call where the SQL was created by the FireDAC
  // SQL preprocessor, as opposed to being a literal expression
  Query.SQL.Text := 'SELECT * FROM tablename WHERE field2 = $1;';
  Query.Params[0].AsString := '4'; // BANG! Argument out of range

我认为可能是由于 FireDAC 宏扩展,所以我在实例化 FDQuery 后添加了以下两行:

Query.ResourceOptions.MacroCreate := False;
Query.ResourceOptions.MacroExpand := False;

不。 那也确实有帮助。 我猜 FireDAC 根本无法识别 $1 是 PostgreSQL 中的有效位置参数。

您需要将符号参数标识符(在您的情况下:accid )放在 SQL.Text 字符串中,而不是位置代码( $1

我刚刚测试了这两个变体。 第一个有效,第二个无效。

var
  MyQ : tfdquery;
begin
  MyQ := Tfdquery.Create(nil);
  MyQ.Connection := dm1.dbMain;
  MyQ.SQL.Text := 'Select * from person where lastname = :lname;';
  MyQ.Params[0].AsString := 'Brodzinsky';
  MyQ.Open();
  ShowMessage('Records found = '+MyQ.RecordCount.ToString);
  MyQ.Close;
  MyQ.Free;
end;

接下来尝试使用位置。 当然,FireDac 没有看到冒号,所以不知道有参数可以创建

var
  MyQ : tfdquery;
begin
  MyQ := Tfdquery.Create(nil);
  MyQ.Connection := dm1.dbMain;
  MyQ.SQL.Text := 'Select * from person where lastname = $1;';
  MyQ.Params[0].AsString := 'Brodzinsky';
  MyQ.Open();
  ShowMessage('Records found = '+MyQ.RecordCount.ToString);
  MyQ.Close;
  MyQ.Free;
end;

首先,person 表中的 11 条记录返回了我的姓氏; 在第二个中,会生成 Argument Out Of Range 错误,因为 SQL 文本中没有指定参数。 注意:我正在访问 MySQL 数据库,但这里的问题是 Delphi 和 FireDac 预处理要发送到数据库服务器的代码。

好的,可能有一种方法可以使用 FireDAC 属性来解决此问题,但我还没有找到。 但是,对于这种特殊情况,SQL 在一种方法中准备好,然后从另一种方法中分配给不同的 FDQuery,我找到了答案。 由于 PostgreSQL 允许命名参数使用数字,例如 :1,我所做的是将 $ 字符替换为 : 字符。

var
  SQLStmt: String;
  FDQuery: TFDQuery;
begin
  SQLStmt :=  'SELECT * FROM tablename WHERE field2 = $1;';
  FDQuery := TFDQuery.Create( nil );
  FDQuery.Connection := FDConnection1;
  FDQuery.SQL.Text := SQLStmt.Replace( '$', ':' );
  FDQuery.Params[0].AsString := 'SomeValue'); // Works!
  ...

而且,是的,如果您的查询包含多个命名参数实例,FireDAC 会用相同的数字替换它。

如果我找到另一个解决方案,我会发布它。 如果其他人提出了使用 FireDAC 属性的解决方案,我会选择该答案作为正确答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM