更改为 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);
with
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 属性将 DataType 属性设置为 ftWideString 或 ftString中的备注FireDAC TFDParam.AsString 文档。似乎参数值分配只是将类型从 ftString 切换到 ftWideString(如原始错误所示)。
DataFormSettings
is a TClientDataSet
在客户端应用程序中,连接到服务器应用程序,其中TDataSetProvider
and 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
);
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
所有数据库中包含正确的数据;它是一个包含 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...
Notes:
- 目前正在 SQL Server 2008 和 Oracle 10 上进行测试,但我预计其他版本也没有什么不同。
- FWIW,
select * from NLS_database_PARAMETERS where parameter like '%CHARACTERSET%'
回报NLS_CHARACTERSET=WE8MSWIN1252
and NLS_NCHAR_CHARACTERSET=AL16UTF16
Query 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;
但这没有帮助。