簡體   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