在切换到FireDAC后,我在MSSQL/Oracle上运行此代码时遇到了问题:
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字符串类型...
但是现在对于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
"What am I missing here? Specifically, I would like to just get the AsString retrievals/assignments to work."请问我错过了什么?具体来说,我想让AsString的检索/赋值起作用。 请注意FireDAC TFDParam.AsString documentation中的“设置AsString属性会将DataType属性设置为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
表格是按以下方式创建的:
FireBird:
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
);
Oracle:
CREATE TABLE TT_FORMSETTINGS
(
TT_FORMSETTINGS_ID NUMBER(10,0) DEFAULT 0 NOT NULL,
TT_EMP_ID NUMBER(10,0),
TT_FORM VARCHAR(50),
TT_VERSION NUMBER(10,0),
TT_VIEWDATA CLOB,
TT_TAG NUMBER(10,0),
TT_TAGTYPE NUMBER(10,0),
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
在所有数据库中都包含正确的数据;它是一个长字符串,包含回车换行符(CRLFs)。\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,
select * from NLS_database_PARAMETERS where parameter like '%CHARACTERSET%'
返回NLS_CHARACTERSET=WE8MSWIN1252
和NLS_NCHAR_CHARACTERSET=AL16UTF16
查询SELECT dump(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,65,54,65,6c,6c,5c,44,65,...
FieldByName().AsANSIString
与FieldByName().AsString
给出相同结果
额外信息:这是一个遗留应用程序,其在 DataFormsettings
TClientDataset
上具有持久字段定义。 TT_VIEWDATA
被定义为一个 TMemoField
:
DataFormsettingsTT_VIEWDATA: TMemoField;
在一个小的测试应用程序中(直接连接到Oracle;不是客户端-服务器),我让Delphi添加字段定义,然后它说:
DataFormsettingsTT_VIEWDATA: TWideMemoField;
如果我在主应用程序中使用它,Oracle可以正常工作,但是对于MSSQL,我会得到“垃圾”结果。
我还尝试设置Oracle连接的映射规则,例如(有很多变化):
with AConnection.FormatOptions.MapRules.Add do
begin
SourceDataType := dtWideMemo;
TargetDataType := dtMemo;
end;
AConnection.FormatOptions.OwnMapRules := true;
但那并没有帮助。
FetchParams
方法来描述参数?这里发生了和 这里 相同的情况(请查看帖子中间部分)。我打赌,如果你删除FetchParams
调用,就不会有任何麻烦了。FireDAC 会自动转换准备好的语句的参数值。但它不允许您准备描述参数、更改参数数据类型并执行该语句。 - VictoriaDataFormsettings
是一个TFDQuery
,并且你运行了你展示的命令。 - Victoria