2017-09-26 19 views
1

은 내가 이전의 데이터 액세스 기술 (SQLDirect)와 이전 버전과의 호환성을 위해 Data type mapping을 적용하는 위해 파이어 버드 데이터베이스에 TFDConnection이 : 런타임시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

나는 그것의 SQL.Text에 INSERT 쿼리를 할당 : 이것은 (물론) 데이터 형식 ftUnknown와 매개 변수와 함께 나에게 params.count=42을 제공

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

.

그런 다음 쿼리 준비를 호출합니다.

이제는 알려진 datetime 매개 변수를 검사 할 경우 ftDateTime이 아닌 params[x].datatype = ftTimeStamp이 표시됩니다. 그래서 쿼리가 필드를보기 위해 데이터베이스로 돌아갈 때 은 매개 변수를 설정할 때 데이터 매핑 규칙을 수신하지 않는 것 같습니다.

이것은 버그입니까? 그 질문의 일부가되지 않도록

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

내가 그 오류를 해결하기 위해 관리 :이 내 코드에서 나중 단계에서

유명한 338 오류가 발생합니다 곤경에 저를 얻었다. 그러나 Params가 데이터 유형 매핑 규칙을 따르도록 기대하면 모든 것이 더 쉬워졌습니다.

답변

0

매핑 규칙 정의를 잘못 정의했습니다. 매개 변수의 경우 대상을 원본으로 변환합니다.

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

그것은 매핑 규칙 것을 추가 가치 : 그래서

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.

은 당신의 정의에 목표 소스를 교환 TIMESTAMP에서 dtDateTimeFLOAT dtDouble에 명령 매개 변수를 매핑하려면 : Data Type Mapping 항목뿐만 아니라 말한다 매개 변수는 유일한 일입니다. 명령 준비 중일 때만 매개 변수에 대한 데이터 유형을 맵핑합니다 (데이터 유형은 매개 변수에 대해 결정 가능해야 함). 그들은 매개 변수 값을 드라이버로 전달할 때 매개 변수 값을 변환하지 않습니다. 이 코드를 고려하십시오

{ 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

와우, 불편합니다.* 데이터를 쿼리 할 때 * 매핑이 예상대로 작동했을 때 (매핑 규칙이 없으면 FireBird TIMESTAMP는 ftTimeStamp로 표시되고 ftDateTime은 규칙으로 표시됨). 필자가 올바르게 이해한다면 : ptInput ParamType으로 매핑하려면 역방향으로 쿼리 매핑을 재정의해야합니다. –

+1

하지만 여기서 말하고 [다른 대답은] (https://stackoverflow.com/a/46432053/512728) 매개 변수 컬렉션을 직접 작성하기 위해 코드를 다시 작성합니다. –

+0

네가 정의한 것은 결과 집합 필드에 대한 맵 규칙이기 때문에 네, 효과가있었습니다. 내가 정의한 것은 매개 변수에 대한 맵 규칙입니다. 오해의 소지가 있지만 여전히 읽을 수 있습니다. 매개 변수의 경우 source는 매개 변수이며 대상 DBMS 필드입니다. 결과 집합 필드의 경우 원본은 DBMS 필드, 대상 결과 집합 필드입니다. 그리고 결과 집합 필드와 매개 변수에 대해 맵 규칙을 사용하려면 각 데이터 유형 매핑 (양방향)에 대해 2 개의 규칙을 정의해야합니다. – Victoria