TAdoQuery.ParseSql не работает в xe4

У меня есть проект в Delphi 7, и я использую TAdoQuery.ParseSql(); для загрузки параметров. Сейчас компилирую в XE4 и тип параметров иногда неправильный. Это действительно ftInteger, но создано как ftSmallint. Что я могу сделать, чтобы решить эту проблему? Моя БД - SQL Server 2008 R2.

Определение таблицы:

CREATE TABLE [dbo].[tblTest]( 
   [sysId] [int] IDENTITY(1,1) NOT NULL,  
   [Code] [nvarchar](50) NOT NULL, 
   [Name] [nvarchar](500) NOT NULL, 
CONSTRAINT [PK_tblTest] 
PRIMARY KEY CLUSTERED ( [sysId] ASC )
   WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
          ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON ) 
   ON [PRIMARY] )
ON [PRIMARY]

Пример данных:

INSERT INTO tblTest ( Code, Name ) VALUES ( 'a1', 'name1' )

Дельфийский код:

ADOQuery.SQL.Text := 'SELECT * FROM tblTest WHERE sysId = :sysId';
AdoQuery.Parameters.ParseSQL(ADOQuery.SQL.Text,True);
AdoQuery.Parameters.ParamByName('sysId').value := -1;
AdoQuery.open;

ConnectionString (база данных: MyDb)

Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial  Catalog=MyDb;Data Source=.

в качестве решения я использую этот код Delphi

AdoQuery.Parameters.ParseSQL(ADOQuery.SQL.Text,false);

И теперь любой орган может объяснить это? есть ли побочный эффект?


person imanShadabi    schedule 17.01.2014    source источник
comment
Какая версия SQL Server? Как выглядит код SQL. Вы используете mdac или sqlncli для подключения к БД?   -  person Mikael Eriksson    schedule 18.01.2014
comment
дублировать без ответа stackoverflow.com/questions/20813585/   -  person Sir Rufo    schedule 18.01.2014
comment
@Mikael, версия sqlserver2008R2, для подключения используйте MDAC.   -  person imanShadabi    schedule 18.01.2014
comment
Подчеркните, что это работало в delphi7   -  person imanShadabi    schedule 18.01.2014
comment
Мне было бы любопытно увидеть код, который идет после ParseSQL, который указывает тип данных параметра и указывает, что он работает в Delphi 7. Когда вы назначаете SQL.Text, если установлено AdoQuery.Connection, ваше приложение будет запрашивать SQL Server для типа. На данный момент тип должен быть ftInteger. При вызове ParseSQL с DoCreate=true список параметров будет удален, а новые параметры будут созданы, но с DataType=ftUnknown. Я тестировал это в Delphi 7 и Delphi XE5. (извините, у меня нет XE4).   -  person David Dubois    schedule 19.01.2014
comment
@ user1008646 Я редактирую код Delphi; я понимаю, что в качестве решения можно использовать AdoQuery.Parameters.ParseSQL(ADOQuery.SQL.Text,false); вместо AdoQuery.Parameters.ParseSQL(ADOQuery.SQL.Text,true);   -  person imanShadabi    schedule 20.01.2014


Ответы (1)


Во-первых, прежде чем я расскажу о ParseSQL, проверьте строку подключения. Между Initial и Catalog есть два пробела. Когда я использовал эту строку подключения, я получил сообщение об ошибке при открытии запроса о том, что tblTest не существует. Удаление лишнего пространства решило эту проблему.

Когда я увидел этот вопрос, я понятия не имел, что делает ParseSQL. Я много лет занимался разработкой Delphi/SQL Server/ADO и никогда не использовал ее. Я подумал, что это будет возможность узнать что-то новое.

Обратите внимание, что все проведенные мной тесты дали одинаковые результаты в Delphi 7 и Delphi XE5. Мне все еще было бы любопытно увидеть какой-нибудь код, который работает в Delphi 7, но не работает в Delphi XE5.

Когда вы выполняете AdoQuery.SQL.Text:='...', если соединение установлено и открыто, ваше приложение создаст параметры и запросит сервер базы данных, чтобы определить их типы. Этот код:

AdoQuery := tAdoQuery . Create(nil);
AdoQuery . Connection := AdoConnection;
ADOQuery.SQL.Text := 'SELECT * FROM tblTest WHERE sysId = :sysId';

aDataType := AdoQuery.Parameters.ParamByName ( 'sysId' ) . DataType;
Msg ( 'Parameter type = ' + DataTypeToString ( aDataType ) );

приведет к:

Parameter type = ftInteger

Обратите внимание, что DataTypeToString — это просто процедура, которую я написал для преобразования tDataType в строку.

function DataTypeToString ( const nDataType : tDataType ) : string;
begin
  Result := GetEnumName ( TypeInfo(tDataType),
                          integer (nDataType) );
end;

Затем выполните этот код.

AdoQuery.Parameters.ParamByName ( 'sysId' ) . Value := -1;
AdoQuery . Open;

Если вы запустите SQL Profiler, вы увидите, какой запрос отправляется на SQL Server:

exec sp_executesql N'SELECT * FROM tblTest WHERE sysId = @P1
',N'@P1 int',-1

Обратите внимание, что @P1 объявлен как int.

Примечание. Если в строке подключения есть два пробела, тип параметра будет отображаться как ftUnknown, а @P1 будет иметь тип smallint. В оставшейся части этого ответа предполагается, что у вас есть правильная строка подключения с одним пробелом.

Что делает вызов ParseSQL с DoCreate=true?

AdoQuery.Parameters.ParseSQL(ADOQuery.SQL.Text,True);

Первое, что он делает, это очищает список параметров. В данном случае это означает, что правильно типизированный параметр, который у нас уже был, уничтожен. ParseSQL затем анализирует SQL и находит параметр. Он создает новый объект tParameter с именем sysID и добавляет его в список. Новый параметр имеет тип ftUnknown.

Зачем кому-то это делать? Если соединение запроса НЕ было установлено или не было ОТКРЫТО, это может быть очень полезно. Список параметров будет построен для вас, после чего вы сможете явно установить их типы данных.

Что, если вместо этого вы должны были выполнить ParseSQL с DoCreate=false:

AdoQuery.Parameters.ParseSQL(ADOQuery.SQL.Text,false);

Ответ: ничего. ParseSQL проанализирует SQL, найдет параметры и вернет такую ​​строку:

SELECT * FROM tblTest WHERE sysId = ?

заменив параметр знаком вопроса. Это не внесет изменений в список параметров. Поскольку ваш код ничего не делает с возвращаемой строкой, конечным результатом является то, что этот вызов ParseSQL не производит изменений.

person David Dubois    schedule 20.01.2014