[英]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.