FireDAC - Как выполнить хранимую процедуру с параметрами по умолчанию?

я создал следующую хранимую процедуру на MS SQL Server

CREATE PROCEDURE sppl_ParamTest
 @ID int = 666
AS
 BEGIN
  SELECT @ID;
 END

И попытка вызвать его с помощью FireDAC (без создания каких-либо параметров):

FCommand:TFDCommand;
...
FCommand.Params.Clear;
FCommand.SQL.Text:='sppl_ParamTest';
FCommand.CommandKind:=skStoredProc
if FCommand.Params.Count=0 then
FCommand.Open;

Но хранимая процедура возвращает NULL (допустим, чтобы вернуть 666)

Как я понял, это вызвано волшебной силой FireDAC для запроса метаданных каждой процедуры до фактического вызова процедуры.

Можно ли решить это?


person Community    schedule 24.01.2017    source источник
comment
Вы можете указать параметры самостоятельно, если включите метафлаг в fetchoptions, это описано в вручную   -  person whosrdaddy    schedule 24.01.2017
comment
Большое спасибо, это сработало   -  person    schedule 24.01.2017


Ответы (2)


Я добавил ваше определение sppl_ParamTest в свой Sql Server 2014 и выполнил следующий код после минимальной настройки FDConnection, чтобы указать его на сервер и базу данных на нем. FDQuery только что появился на палитре компонентов, и установлено только его свойство Connection.

procedure TForm1.FormCreate(Sender: TObject);
begin
  FDQuery1.SQL.Text := 'sppl_ParamTest';
  FDQuery1.Open;
  Caption := FDQuery1.Fields[0].AsString;
end;

В заголовке формы отображается 666, как и ожидалось.

Частичный DFM (имя пользователя и пароль опущены):

  object FDConnection1: TFDConnection
    Params.Strings = (
      'Database=MATest'
      'Server=MAT410\ss2014'
      'DriverID=MSSQL')
    LoginPrompt = False
    Left = 32
    Top = 16
  end
  object FDQuery1: TFDQuery
    Connection = FDConnection1
    Left = 104
    Top = 16
  end

Обновление Я думаю, что проблема ОП, скорее всего, возникает из-за недостатка в реализации TFDCommand и TFDStoredProc. выполнение

sppl_ParamTest по умолчанию

в Sql Server Management Studio правильно возвращает

666

То же самое можно сказать и об открытии FDQuery с sppl_ParamTest default (или просто sppl_ParamTest) в качестве текста команды.

Однако, если для CommandText TFDCommand установлено то же значение, вызов Execute приводит к этой ошибке.

Не удалось найти хранимую процедуру «MATest.dbo.sspl_ParamTest по умолчанию»

Равным образом, делая

FDStoredProc1.ParamByName('@ID').Value := 'default';

(неудивительно) провоцирует ошибку

Не удалось преобразовать вариант типа (String) в тип (Integer)

при вызове FDStoredProc.Open и до сих пор сопротивлялся моим попыткам установить тип параметра, который будет принимать «по умолчанию» и правильно выполнять sp.

Кроме того, попытки вызвать FDCommand с EmptyParam в качестве значения входного параметра не возвращают значение 666.

person MartynA    schedule 24.01.2017
comment
Вы используете запрос для выполнения хранимой процедуры. Не FDCommand. FDCommand используется для заполнения набора данных In-Mem. - person ; 24.01.2017
comment
Ваш вопрос был Возможно ли решить это? Мой ответ: да, используйте FDQuery, и проблема не возникнет. - person MartynA; 24.01.2017
comment
Я не могу использовать запросы для заполнения наборов данных в памяти. Ваше решение похоже на изменение текста на «exec sspl_paramtest». - person ; 24.01.2017
comment
Ну, вы не упомянули наборы данных в памяти, но в любом случае вы определенно можете заполнить их из FDQuery. Iirc, вы просто присваиваете свойство Data одного другому. - person MartynA; 24.01.2017
comment
Почему бы и нет? В чем проблема заполнить FDMemDataset результатом FDQuery? Например, вы можете использовать FDMemDataset1.CopyDataset для копирования этих данных. - person Marc Guillot; 24.01.2017
comment
Потому что изменение компонента на Query для вызова StoredProcedure не является правильным способом передачи параметра по умолчанию. Query позволяет использовать SQL-инъекции и, по сути, не предназначен для использования так, как вы предлагаете. - person ; 24.01.2017
comment
Валерий, Query можно выполнять без опасности SQL-инъекций, вам просто нужно определить его параметры, как в хранимой процедуре (вместо того, чтобы конкатенировать значения непосредственно в SQL.Text). Или, в данном случае, вообще без параметров, чтобы никогда не было внедрено вредоносного кода. И да, хранимые процедуры также предназначены для вызова операторов SQL, как показано в примерах в документации MS technet.microsoft.com/en-us/library/ms189330(v=sql.105).aspx - person Marc Guillot; 24.01.2017
comment
Комментарий о внедрении Sql кажется мне ерундой. Он не более подвержен внедрению Sql, чем параметризованный запрос. - person MartynA; 24.01.2017
comment
Да, я могу использовать Query. Это означает, что я никогда не должен использовать TFDStoredProcedure или TFDCommand для вызова StoredProcs, поскольку они не могут вызывать их правильно. Не думайте, что это хорошее решение. - person ; 24.01.2017
comment
Не думаю, что это хорошее решение. Конечно, правильный вывод состоит в том, что реализация TFDCommand ошибочна? - person MartynA; 24.01.2017
comment
Ваше решение состоит в том, чтобы использовать другой компонент. И перестаньте использовать TFDStoredProcedure/TFDCommand, для чего они и были созданы. Поскольку они не могут правильно вызывать хранимые процедуры. Что является совершенно неправильным способом решения этой проблемы. В этом случае я также могу использовать TADOStoredProc. - person ; 24.01.2017
comment
1. FireDac вызывает недокументированную хранимую процедуру - sp_columns_100 (с sppl_ParamTest в качестве параметра, используйте профилировщик) 2. Заполняет свою собственную коллекцию Params значениями NULL. 3. Вызвать настоящую хранимую процедуру. Теперь я ищу способ предотвратить 1,2 - person ; 24.01.2017
comment
@Valeriy.B, см. мой комментарий под вашим вопросом. - person whosrdaddy; 24.01.2017

Установка этого параметра на

FetchOptions.Items:=[]

or

FetchOptions.Items := FetchOptions.Items - [fiMeta]

Не позволит FireDac запрашивать метаданные и позволит использовать параметры по умолчанию.

Благодаря whosrdaddy

person Community    schedule 24.01.2017
comment
Не могли бы вы объяснить: какой компонент, FDCommand или FDStoreProc, который вы используете, решает вашу проблему, как вы заставляете его использовать параметры по умолчанию и как вы получаете доступ к результатам вызова для получения значения 666? - person Alex James; 25.01.2017
comment
Вы можете использовать любой FDCommand или FDStoredProc. FDStoredProc.ProceudreName:='sppl_ParamTest'; FDStoredProc.FetchOptions.Items:=[]; FDStoredProc.Открыть; ShowMessage(FDStoredProc.Fields[0].AsString); //666 - person ; 25.01.2017