Я работаю с SQL Server 2014 и пытаюсь выполнить (динамическую) хранимую процедуру из структуры сущностей.
Моя хранимая процедура имеет следующие входные параметры:
@Username NVARCHAR(100),
@Number DECIMAL,
@PageIndex INT = 1,
@PageSize INT = 20,
@Field1 NVARCHAR(12) = NULL,
@Field2 NVARCHAR(60) = NULL,
@Field3 NVARCHAR(60) = NULL,
@Field4 NVARCHAR(60) = NULL,
@Field5 NVARCHAR(60) = NULL,
@Field6 NVARCHAR(60) = 'ABC',
@Field7 NVARCHAR(4) = 'ABC',
@IsCountOnly BIT = 0,
@IsFilterOnly BIT = 0
EF генерирует следующий запрос (полученный с помощью профилировщика SQL) на основе параметров, которые я добавил в свой массив, но обратите внимание, что я добавляю только те, которые мне нужны, поскольку большинство из них являются необязательными.
exec sp_executesql
N'EXEC MySp @Username, @Number, @IsCountOnly',
N'@Username nvarchar(100), Number decimal(6,0), @IsCountOnly bit',
@Username=N'[email protected]', @Number=12345, @IsCountOnly=1
Когда я передаю @Username, @Number, которые являются обязательными, а затем передаю @IsCountOnly, моя хранимая процедура выполняется, но возвращает неправильные результаты, поскольку кажется, что значение, переданное через @IsCountOnly, обрабатывается как @PageIndex, а не @IsCountOnly.
Обратите внимание, что если я вызову EXEC непосредственно в SQL Server Management Studio:
EXEC [dbo].[MySp]
@Username = N'[email protected]',
@Number = 12345,
@IsCountOnly = 1
GO
Он работает так, как ожидалось.
Чтобы проверить, была ли проблема в этом, я включил все параметры в exec sp_executesql N'EXEC ..., и это сработало, как и ожидалось, но кажется излишним определять все параметры, когда в некоторых сценариях нужны только некоторые из них.
Это ошибка в SQL при работе с exec sp_executesql и EXEC или я что-то не так делаю??
Спасибо.
ОБНОВЛЕНИЕ-1:
Обратите внимание: когда я говорю, что при передаче всех параметров все работало, как и ожидалось, это не совсем верно, так как когда я передаю null для необязательных параметров, на самом деле не используются предоставленные значения по умолчанию, что в некоторой степени имеет смысл, но это означает, что мне придется передавать правильные значения по умолчанию в моем проекте .NET, а не через SQL, что просто не идеально.
Ни один из параметров не указывает, какой параметр они передают, поэтому они основаны на порядковой позиции, а не на имени переменной. Третий параметр в вашей SP — @PageIndex, поэтому @IsCountOnly (которое является переданным третьим значением) будет рассматриваться как значение для @PageIndex; а остальные будут иметь значение по умолчанию. Это похоже на ошибку сопоставления в коде вашего приложения.
NULL. NULL все еще значение, просто неизвестное.
@JeroenMostert ты был в ударе! Быстро изменил мою функцию, которая создает список полей для моих необязательных полей, чтобы включить одно и то же поле, и это сработало сразу! Спасибо


Вы можете использовать именованные параметры:
N'EXEC MySp @Username=@Username, @Number=@Number, @IsCountOnly=@IsCountOnly''
Я не генерирую этот код. Entity framework есть и это моя проблема. поскольку он генерирует запрос как «exec sp_executesql N'EXEC....», как упоминается в вопросе, который вызывает проблему. Это вызов, который у меня есть на моем уровне данных: DbContext.Database.SqlQuery("EXEC MySP @Username, @Number, " + optionalParameters, parameterList.ToArray()) где необязательные параметры — это просто дополнительные устанавливаемые @Field, а список параметров содержит массив SqlParameters.
Я попытаюсь вызвать его через .SqlQuery и посмотреть, что произойдет, просто сначала жестко запрограммировав его, а не передавать массив параметров, поскольку это необязательно.
К сожалению, это не работает. так как sp_executesql ожидает передачи параметров.
@Thierry: см. этот вопрос, чтобы узнать больше о том, как конкретно работает EF.
Как заявил @JeroenMostert, использование параметров имени является решением. Спасибо еще раз.
Вы делаете это неправильно (извините). Вместо этого используйте
EXEC MySp @Username = @Username, @Number = @Number, @IsCountOnly = @IsCountOnly. Это сбивает с толку, но ваш синтаксис фактически передает параметры по порядковому номеру, просто заполняя эти порядковые значения параметрами самого параметризованного оператораEXEC.