2017-09-26 5 views
1

Ich habe eine TFDConnection zu einer Firebird-Datenbank, für die ich Data type mapping für die Abwärtskompatibilität mit früheren Datenzugriffstechnologie (SQLDirect) gelten:FireDAC-Zuordnungsregeln gelten nicht für Parameter?

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; 

Zur Laufzeit erstelle ich eine TFDQuery, die ich zu diesem TFDConnection verknüpfen.
Ich kann sehen, dass es die Zuordnungsregeln erbt: FormatOptions.MapRules.count=2

ich eine INSERT-Abfrage an seinen SQL.Text zuweisen:

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,...) 

Das ist mir params.count=42 mit Parametern mit Datentyp ftUnknown gibt (natürlich).

Ich rufe dann Prepare für die Abfrage. Wenn ich nun einen bekannten Datetime Parameter überprüfe, sehe ich params[x].datatype = ftTimeStamp, nicht ftDateTime. Also, wenn die Abfrage zurück in die Datenbank geht, um die Felder zu sehen, scheint es nicht auf die Datenzuordnungsregeln bei der Einrichtung der Parameter zu hören.

Ist das ein Fehler?

In einer späteren Phase in meinem Code das hat mir in Schwierigkeiten, die sich in der berühmten 338-Fehler:

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

ich um diesen Fehler zu arbeiten, verwaltet werden, so dass nicht Teil der Frage ist. Aber ich würde erwarten, dass die Params auch den Regeln für das Mapping von Datentypen folgen, was all das erleichtert hätte.

Antwort

0

Sie haben die Zuordnungsregeldefinitionen einfach falsch definiert. Für Parameter ist die Transformation von Ziel in Quelle. Das Data Type Mapping Thema sagt, dass auch:

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.

So Befehlsparameter von TIMESTAMP zu dtDateTime und FLOAT-dtDouble nur tauschen Quelle mit Ziel in Ihrer Definition zur Karte:

{ 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; 

Es lohnt fügen hinzu, dass Zuordnungsregeln für Parameter tun das einzige. Sie bilden nur Datentypen für Parameter ab, wenn der Befehl vorbereitet wird (Datentypen müssen für sie bestimmbar sein). Sie konvertieren keine Parameterwerte, wenn sie an den Treiber übergeben werden. Betrachten Sie diesen Code:

{ 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; 

So wie Sie sehen können, ist es ziemlich viel Aufwand für so gut wie nichts (Wechsel bestimmten Parameterdatentyp in einen anderen nur). Parameterwerte werden unabhängig von Zuordnungsregeln automatisch konvertiert. Also, auch wenn Sie Ihre Parameter Datentyp nicht DBMS-Datentyp entspricht, wird aber konvertierbar sein wird FireDAC einfach konvertiert es für dich, egal was (diese Magie innerhalb ConvertRawData Methode):

{ 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; 

Also auch hier ist würde wiederholen, dass Parametersammlungen manuell und nicht vom DBMS aus einem vorbereiteten Befehl definiert werden sollten (der Entwickler muss wissen, welche Werte in welche Felder gefüllt werden).

+0

O, wow, das ist unbequem.Bei der Abfrage von * Daten funktionierte mein Mapping wie erwartet (Ohne die Mapping-Regeln erscheint ein FireBird TIMESTAMP als ftTimeStamp; mit den Regeln als ftDateTime). Wenn ich Sie richtig verstehe: Wenn ich dann nach ptInput ParamType mappen möchte, muss ich das Mapping für die Abfrage in umgekehrter Richtung überschreiben. –

+1

Aber wie Sie hier sagen und [in Ihrer anderen Antwort] (https://Stackoverflow.com/a/46432053/512728) werde ich meinen Code umschreiben, um die Parameter-Sammlung selbst zu erstellen. –

+0

Ja, es hat funktioniert, weil Sie Kartendetails für Ergebnisfelder definiert haben. Was ich definiert habe, sind Map-Regeln für Parameter. Es ist ein bisschen irreführend, aber immer noch lesbar. Für Parameter ist Quelle Parameter, Ziel-DBMS-Feld. Für das Resultset-Feld ist die Quelle das DBMS-Feld, das Ziel-Resultset-Feld. Wenn Sie sowohl für Ergebnismengenfelder als auch für Parameter Kartenregeln verwenden möchten, müssen Sie für jede Datentypzuordnung (für beide Richtungen) 2 Regeln definieren. – Victoria

Verwandte Themen