2017-09-26 82 views
1

我有一個TFDConnection爲我申請Data type mapping爲了向後兼容以前的數據訪問技術(SQLDirect)一個Firebird數據庫:FireDAC映射規則不適用於參數?

with FormatOptions.MapRules.Add do  // TIMESTAMP will be ftDateTime instead of ftTimeStamp 
begin 
    SourceDataType := dtDateTimeStamp; 
    TargetDataType := dtDateTime; 
end; 
with FormatOptions.MapRules.Add do  // FLOAT will be ftFloat instead of ftSingle 
begin 
    SourceDataType := dtSingle; 
    TargetDataType := dtDouble; 
end; 
FormatOptions.OwnMapRules := true; 

在運行時創建,我鏈接到一個TFDConnection TFDQuery。
我可以看到,它繼承了映射規則:FormatOptions.MapRules.count=2

我分配一個INSERT查詢到其SQL.Text:

insert into TT_ACT (TT_ACT_ID,TT_PARENT_ID,TT_FROMDATE,TT_TODATE,TT_NAME,TT_NR,TT_CODE,TT_GROUP...) 
values (:TT_ACT_ID,:TT_PARENT_ID,:TT_FROMDATE,:TT_TODATE,:TT_NAME,:TT_NR,:TT_CODE,:TT_GROUP,...) 

這給了我params.count=42與數據類型ftUnknown(當然)參數。

然後我打電話給Prepare進行查詢。

如果我現在檢查一個已知的日期時間參數,我看到params[x].datatype = ftTimeStamp,而不是ftDateTime。 因此,當查詢返回到數據庫查看字段時,在設置參數時似乎沒有監聽數據映射規則

這是一個錯誤?

在我的代碼,這後一階段讓我陷入困境,成就了著名的338錯誤:

[FireDac][Phys][IB]-338 Param [TT_FROMDATE] type changed from [ftSQLTimeStamp] to [ftDateTime]. Query must be reprepared. 

我設法解決這個錯誤,所以這不是問題的一部分。但我希望Params也遵循數據類型映射規則,這將使所有這些變得更容易。

回答

0

您剛剛錯誤定義了映射規則定義。對於參數來說,它是將目標轉化爲來源。該Data Type Mapping話題說還有:

In case of a command parameter, the rule defines a transformation of a target data type, specified by an application, into a source data type, supported by a driver.

所以要命令參數映射從TIMESTAMPdtDateTimeFLOATdtDouble只是交換源與目標在你的定義:

{ FLOAT → dtDouble in parameters } 
with FormatOptions.MapRules.Add do 
begin 
    SourceDataType := dtDouble; { TFDParam.DataType } 
    TargetDataType := dtSingle; { Firebird FLOAT } 
end; 
{ TIMESTAMP → dtDateTime in parameters } 
with FormatOptions.MapRules.Add do 
begin 
    SourceDataType := dtDateTime; { TFDParam.DataType } 
    TargetDataType := dtDateTimeStamp; { Firebird TIMESTAMP } 
end; 
{ enable custom map rules } 
FormatOptions.OwnMapRules := True; 

值得補充說,映射規則參數做唯一的事情。在準備命令時,它們只映射參數的數據類型(數據類型必須可以確定)。它們在傳遞給驅動程序時不會轉換參數值。考慮以下代碼:

{ Firebird FLOAT equals to dtSingle data type, map it to dtDouble } 
with FDQuery1.FormatOptions.MapRules.Add do 
begin 
    SourceDataType := dtDouble; 
    TargetDataType := dtSingle; 
end; 
FDQuery1.FormatOptions.OwnMapRules := True; 
{ setup the command; MyFloat field is Firebird FLOAT } 
FDQuery1.SQL.Text := 'INSERT INTO MyTable (MyFloat) VALUES (:MyFloat)'; 
{ rules are applied when preparing command, so let's prepare it } 
FDQuery1.Prepare; 
{ now the parameter data type should be dtDouble instead of dtSingle } 
if FDQuery1.ParamByName('MyFloat').DataType = dtDouble then 
    ShowMessage('Parameter is of dtDouble data type'); 
{ but you can easily change the parameter data type to another, e.g. by mistake; 
    this will change data type to dtSingle, so the whole mapping effort is lost } 
FDQuery1.ParamByName('MyFloat').AsSingle := 1.2345; 
{ if this would execute (which does not because the parameter data type has been 
    changed since the command preparation), parameter map rules would still not be 
    involved in converting parameter value for the driver } 
FDQuery1.ExecSQL; 

因此,大家可以看到,它是幾乎沒有(改變決定的參數的數據類型到另一隻)相當多的努力。參數值自動轉換,無論映射規則。所以,即使你的參數的數據類型不匹配DBMS數據類型,但將是敞篷車,FireDAC會簡單地轉換爲你不管是什麼(這個神奇的是裏面ConvertRawData法):

{ assume MyFloat FLOAT, MyTimeStamp TIMESTAMP in Firebird } 
FDQuery1.SQL.Text := 'INSERT INTO MyTable (MyFloat, MyTimeStamp) VALUES (:MyFloat, :MyTimeStamp)'; 
{ setup parameter data types badly to be dtDouble and dtDateTime } 
FDQuery1.ParamByName('MyFloat').AsFloat := 1.2345; 
FDQuery1.ParamByName('MyTimeStamp').AsDateTime := Now; 
{ and execute; parameter values will be converted automatically to DBMS data types 
    dtDouble → dtSingle and dtDateTime → dtDateTimeStamp } 
FDQuery1.ExecSQL; 

所以我在這裏也會重複一次,參數集合應該手動定義,而不是由DBMS從準備好的命令中定義(開發人員必須知道填充到哪些字段中的值)。

+0

O,哇,這很不方便。當查詢*數據時,我的映射按預期工作(沒有映射規則,FireBird TIMESTAMP顯示爲ftTimeStamp;規則爲ftDateTime)。如果我理解正確:如果我然後想要映射ptInput ParamType,我必須在相反的方向覆蓋查詢的映射。 –

+1

但正如你在這裏說的和[在你的其他答案](https://stackoverflow.com/a/46432053/512728)我將重寫我的代碼來自己構建參數集合。 –

+0

是的,它的工作原理是您定義的是結果集字段的映射規則。我定義的是參數的映射規則。這有點誤導,但仍然可讀。對於參數,源是參數,目標DBMS字段。對於結果集字段,源是DBMS字段,目標結果集字段。如果你想爲結果集字段和參數使用映射規則,則需要爲每個數據類型映射(對於兩個方向)定義2條規則。 – Victoria