В случае столбца набора результатов каждое правило определяет преобразование типа данных источника, возвращаемого драйвером, в целевой тип, предпочтительный для приложения. В случае параметра команды правило определяет преобразование целевого типа данных, заданного приложением, в тип данных источника, поддерживаемый драйвером. Все правила, кроме именных, работают в обоих случаях в двух направлениях.
перехода на 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 String по умолчанию ...
Но теперь S-определение не работает для Oracle (не FireBird или MSSQL) в том смысле, что я вижу возвращение двухбайтовых символов. 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
это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
содержит правильные данные во всех базах данных; это длинная строка, содержащая 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,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 содержит байты ASCII для кодовой страницы Win1252: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;
В небольшом 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;
но это не помогло.