with DataFormsettings do begin Close; if Params.Count=0 then FetchParams; Params.ParamByName('TT_EMP_ID').Asinteger := AEmpID; Params.ParamByName('TT_FORM').AString := UpperCase(AKey); Open; if (RecordCount>0) then S := FieldByName('TT_VIEWDATA').Asstring; end;
AKey和S都是字符串.
Open语句给出错误
[FireDAC][Phys][MSsql]-338 Param type changed from [ftString] to [ftWidestring] [FireDAC][Phys][Ora]-338 Param type changed from [ftString] to [ftWidestring]
连接到MSsql或Oracle数据库时;连接到FireBird时没有.
在FetchParams之后,DataFormsettings.params [1] .datatype总是一个ftString.
如果我更换
Params.ParamByName('TT_FORM').AString := UpperCase(AKey);
同
Params.ParamByName('TT_FORM').Value := UpperCase(AKey);
… Open语句中没有错误.虽然我没有真正理解错误,但我认为这已经解决了.毕竟,这应该是所有默认的Delphi String类型……
但是现在,对于Oracle(而不是FireBird或MSsql)来说,S分配失败了,因为我看到2字节字符被返回. S包含:
\'#0'S'#0'o'#0'f'#0't'#0'w'#0'a'#0'r'#0'e'#0'\'#0'T'#0'i'#0'm'#0'e'#0'T'#0'e'#0'l'#0'l'#0'...
我可以用例如
S := TEncoding.Unicode.GetString(FieldByName('TT_VIEWDATA').AsBytes);
对于Oracle,但(当然)在使用其他两种不起作用的数据库类型时:
No mapping for the Unicode character exists in the target multi-byte code page
我在这里想念的是什么?具体来说,我想让AsString检索/分配工作.
请注意,设置AsString属性会将数据类型属性设置为FireDAC TFDParam.AsString documentation中的ftWideString或ftString备注.似乎参数值赋值只是将类型从ftString切换为ftWideString(由原始错误指示).
DataFormSettings是客户端应用程序中的TClientDataSet,连接到TDataSetProvider和TFDQuery所在的服务器应用程序.查询是
select TT_FORMSETTINGS_ID,TT_EMP_ID,TT_FORM,TT_VERSION,TT_VIEWDATA from TT_FORMSETTINGS where TT_EMP_ID=:TT_EMP_ID and TT_FORM=:TT_FORM
表格创建如下:
火鸟:
CREATE TABLE TT_FORMSETTINGS ( TT_FORMSETTINGS_ID INTEGER DEFAULT 0 NOT NULL,TT_EMP_ID INTEGER,TT_FORM VARCHAR(50),TT_VERSION INTEGER,TT_VIEWDATA BLOB SUB_TYPE TEXT SEGMENT SIZE 80,TT_TAG INTEGER,TT_TAGTYPE INTEGER,TT_TAGDATE TIMESTAMP );
甲骨文:
CREATE TABLE TT_FORMSETTINGS ( TT_FORMSETTINGS_ID NUMBER(10,0) DEFAULT 0 NOT NULL,TT_EMP_ID NUMBER(10,0),TT_VERSION NUMBER(10,TT_VIEWDATA CLOB,TT_TAG NUMBER(10,TT_TAGTYPE NUMBER(10,TT_TAGDATE DATE );
MSsql:
CREATE TABLE TT_FORMSETTINGS ( TT_FORMSETTINGS_ID INTEGER NOT NULL CONSTRAINT TT_C0_FORMSETTINGS DEFAULT 0,TT_EMP_ID INTEGER NULL,TT_FORM VARCHAR(50) NULL,TT_VERSION INTEGER NULL,TT_VIEWDATA TEXT NULL,TT_TAG INTEGER NULL,TT_TAGTYPE INTEGER NULL,TT_TAGDATE DATETIME NULL );
我已经检查过TT_VIEWDATA在所有数据库中包含正确的数据;它是一个包含CRLF的长字符串:
\Software\TimeTell\Demo8\Forms\TFormTileMenu'#$D#$A'Version,1,80502'#$D#$A'\Software\TimeTell\Demo8\Forms\TFormTileMenu\TileControlMenu'#$D#$A'\Software\TimeTell\Demo8\Forms\TFormTileMenu\TileControlMenu\FormTileMenu.TileControlMenu'#$D#$A'Version,4,2'#$D#$A'\Software\TimeTell\Demo8\Forms\TFormTileMenu\TileControlMenu\FormTileMenu.TileControlMenu...
笔记:
>目前正在测试sql Server 2008和Oracle 10,但我希望这与其他版本没有什么不同.
> FWIW,从NLS_database_PARAMETERS中选择*,其中’%CHARACTERSET%’等参数返回NLS_CHARACTERSET = WE8MSWIN1252和NLS_NCHAR_CHARACTERSET = AL16UTF16
查询SELECT转储(dbms_lob.substr(tt_viewdata,100,1),1016),tt_viewdata FROM tt_formsettings确认CLOB包含Win1252代码页的ASCII字节:Typ = 1 Len = 100 CharacterSet = WE8MSWIN1252:5c,53,6f,66,74,77,61,72,65,5c,54,69,6d,6c,6C,5C,44,…
> FieldByName().AsANSIString提供与FieldByName().AsString相同的结果
附加信息:这是一个遗留应用程序,在DataFormsettings TClientDataset上具有持久字段定义. TT_VIEWDATA定义为TMemoField:
DataFormsettingsTT_VIEWDATA: TMemoField;
在一个小的testapp(直接连接到Oracle;而不是客户端 – 服务器)我让Delphi添加字段定义然后它说:
DataFormsettingsTT_VIEWDATA: TWideMemoField;
如果我在主应用程序中使用它,Oracle工作正常,但后来我得到MSsql的“垃圾”.
我还尝试为Oracle连接设置映射规则,如(许多变体):
with AConnection.FormatOptions.MapRules.Add do begin SourceDataType := dtWideMemo; TargetDataType := dtMemo; end; AConnection.FormatOptions.OwnMapRules := true;
但这没有帮助.
在FireDAC.Stan.Option中:
procedure TFDFormatOptions.ColumnDef2FieldDef() ... dtWideHMemo: // Here was ftOraClob,but then will be created TMemoField,// which does not know anything about Unicode. So,I have // changed to ftFmtMemo. But probably may be problems ... ADestFieldType := ftWideMemo;
的确,可能是问题.
解决方案是添加将dtWideHMemo转换为dtMemo的映射规则.
之后,读取和写入CLOB .AsString工作正常.
在Embarcadero Quality Portal报道为RSP-19600.
为了完整性:因为我的其他答案中提到的映射不再处于活动状态,您必须使用.Value而不是.AsString更改对参数的访问.