Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Параметры передают значения команде отдельно от её Transact-SQL (T-SQL) текста. Используйте объекты SqlParameter вместо конкатенации или интерполяции значений в SQL-операторы. Параметры помогают защититься от SQL-инъекций и сохраняют тип значения в базе данных.
Примеры в этой статье предполагают, что открытый SqlConnection с именем connection нацелен на образцовую базу данных AdventureWorks.
Примеры C# требуют using Microsoft.Data.SqlClient;. Примеры, которые используют SqlDbType также требуют using System.Data;.
Добавить входные параметры
Добавьте параметр для каждого заполнителя значения в тексте команды. Укажите тип параметра SQL Server и присвоите ему значение:
const string sql = """
SELECT ProductID, Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
AND ListPrice >= @minimumPrice
ORDER BY ListPrice;
""";
using var command = new SqlCommand(sql, connection);
command.Parameters.Add("@subcategoryId", SqlDbType.Int).Value = 2;
command.Parameters.Add("@minimumPrice", SqlDbType.Money).Value = 1_000m;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetInt32(0)}: {reader.GetString(1)} ({reader.GetDecimal(2):C})");
}
Используйте тот же регистр для имени параметра в тексте команды и в SqlParameter. SQL Server сопоставляет имена переменных, используя серверную колляцию, поэтому несоответствие приводит к ошибке «Must declare the scalar variable» на сервере с чувствительной к регистру колляцией.
Работа с заполнителями параметров
Microsoft. Data.SqlClient использует именованные параметры в виде @parameterName. Позиционные заполнители со знаком вопроса (?) не поддерживаются.
Заполнители параметров представляют значения, а не идентификаторы SQL или синтаксис. Нельзя использовать параметр для имени таблицы, имени столбца, направления сортировки или целого SQL-фрагмента. Если приложение динамически выбирает идентификатор, проверьте его по списку разрешений и добавьте его в текст команды только после проверки. Продолжайте передавать все значения данных как параметры.
Для текстовых команд Microsoft. Data.SqlClient отправляет параметризованные операторы на SQL Server через sp_executesql. SQL Server может повторно использовать план выполнения, если текст оператора и определения параметров остаются прежними.
Указание типов данных параметров
Устанавливайте SqlDbType явно, когда приложение знает целевой тип SQL Server. Также устанавливайте метаданные, специфичные для типа, такие Sizeкак , Precision, и Scale при необходимости.
Этот пример соответствует столбцам nvarchar(50) и datetime в Person.Person:
const string sql = """
SELECT BusinessEntityID, FirstName, LastName
FROM Person.Person
WHERE LastName = @lastName
AND ModifiedDate >= @modifiedSince
ORDER BY BusinessEntityID;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter lastName = command.Parameters.Add(
"@lastName",
SqlDbType.NVarChar,
50);
lastName.Value = "O'Brien";
SqlParameter modifiedSince = command.Parameters.Add(
"@modifiedSince",
SqlDbType.DateTime);
modifiedSince.Value = new DateTime(2013, 1, 1);
Сопоставление метаданных параметров с целевым столбцом позволяет избежать неявных преобразований и предотвращает изменение определения параметра из-за изменения длины строки или десятичного масштаба.
Для десятичных значений установите точность и масштаб явно. Столбец Weight в Production.Product использует decimal(8, 2):
const string sql = """
SELECT ProductID, Name, Weight
FROM Production.Product
WHERE Weight >= @minimumWeight
ORDER BY Weight;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter minimumWeight = command.Parameters.Add(
"@minimumWeight",
SqlDbType.Decimal);
minimumWeight.Precision = 8;
minimumWeight.Scale = 2;
minimumWeight.Value = 10.25m;
Передавать значения NULL базы данных
Назначьте Value для отправки базы данных NULL. C# null не соответствует SQL Server NULL для обычных скалярных параметров:
const string sql = """
SELECT SalesOrderID, OrderDate, SalesPersonID
FROM Sales.SalesOrderHeader
WHERE (@salesPersonId IS NULL OR SalesPersonID = @salesPersonId)
ORDER BY SalesOrderID;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter salesPersonId = command.Parameters.Add(
"@salesPersonId",
SqlDbType.Int);
int? selectedSalesPersonId = null;
salesPersonId.Value = selectedSalesPersonId.HasValue
? selectedSalesPersonId.Value
: DBNull.Value;
Выборочно используйте выведенные метаданные
Метод AddWithValue выводит метаданные параметров из значения во время выполнения. Инференс удобен, когда предполагаемые метаданные стабильны и соответствуют типу базы данных. Он может создавать различные определения параметров при изменении длины строк, десятичной точности или других характеристик значения.
Предпочтительно использовать Add с явным SqlDbType для производственных команд, целевая схема которых известна. Не передавайте C# null в AddWithValue; указывайте тип и вместо этого назначьте DBNull.Value.
Повторно использовать параметры команды
Создайте параметр один раз и измените только его Value при выполнении одной и той же команды с разными значениями:
const string sql = """
SELECT TOP (1) Name, ListPrice
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ListPrice DESC;
""";
using var command = new SqlCommand(sql, connection);
SqlParameter subcategoryId = command.Parameters.Add(
"@subcategoryId",
SqlDbType.Int);
foreach (int id in new[] { 1, 2, 3 })
{
subcategoryId.Value = id;
using SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
Console.WriteLine($"{id}: {reader.GetString(0)}");
}
}
Не добавляйте другой параметр с таким же именем при каждом выполнении. Используй существующий параметр или очисти коллекцию перед её повторной сборкой.
Установить направление параметра
Свойство Direction определяет, как команда использует параметр. Установите значение ParameterDirection:
| Direction | Использовать |
|---|---|
| Input | Отправляет значение в инструкцию или сохранённую процедуру. Это значение по умолчанию. |
| Output | Получает значение из выходного параметра сохранённой процедуры. |
| InputOutput | Отправляет начальное значение и получает обновлённое значение. |
| ReturnValue | Получает целочисленное значение из оператора T-SQL RETURN . |
Для параметров вывода, входа/вывода и возвратных значений читайте Value только после завершения выполнения команды. Если команда возвращает строки, закройте или освободите SqlDataReader перед чтением этих значений.
Для полных примеров хранимых процедур см. Изменение данных с помощью хранимых процедур.
Используйте параметры с хранимой процедурой
Установите StoredProcedure и используйте имена параметров процедуры. В этом примере вызывается процедура dbo.uspGetEmployeeManagers, включённая в AdventureWorks:
using var command = new SqlCommand(
"dbo.uspGetEmployeeManagers",
connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(
"@BusinessEntityID",
SqlDbType.Int).Value = 6;
using SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(
$"{reader.GetString(2)} {reader.GetString(3)}");
}
Имя параметра должно совпадать с именем, объявленным в хранимой процедуре.
Настройка табличнозначных параметров
Параметр с табличным значением отправляет несколько строк в сохранённую процедуру или параметризованную инструкцию. Для настройки одной:
- Задайте
SqlDbType.Structured. - Установите для TypeName значение "определяемый пользователем тип таблицы базы данных".
- Назначьте источник строки DataTable, DbDataReader или
IEnumerable<SqlDataRecord>.
DataTable с определёнными столбцами и без строк отправляет пустую таблицу. Пустой IEnumerable<SqlDataRecord> вызывает ArgumentException; укажите C# null для отправки нулевых строк для этой формы ввода. Не назначайте DBNull.Value параметру с табличным значением.
Для создания типов, отображения строк и полных примеров см. параметры с табличными значениями.
Настроить потоковые значения
Присваивайте Stream, TextReader или XmlReader к Value, чтобы постепенно увеличивать значение на большую величину. Для передачи с ограничением памяти используйте тип параметра (max), xml или json. Microsoft.Data.SqlClient буферизирует источник перед выполнением для несимвольных(max) и бинарных типов, а также для устаревших типов больших объектов.
Тип параметра должен соответствовать значению:
| Value | Совместимые SqlDbType значения |
|---|---|
| Stream |
Binary, VarBinary, или устаревший тип Image |
| TextReader |
Char, NChar, NVarChar, VarChar, устаревшие типы Text и NText, Xml, или Json |
| XmlReader |
Char, NChar, NVarChar, VarChar, устаревшие типы Text и NText, Xml, или Json |
Microsoft.Data.SqlClient выдает ArgumentException, InvalidCastException или SqlTypeException, когда тип объекта SqlDbType или заявленный размер несовместимы. Полные примеры загрузки и скачивания смотрите в разделе поддержка потоковой передачи SqlClient.
Получение сведений о параметрах
DeriveParametersзапрашивает в SQL Server метаданные параметров хранимой процедуры и заменяет существующий набор параметров команды:
using var command = new SqlCommand(
"dbo.uspGetEmployeeManagers",
connection);
command.CommandType = CommandType.StoredProcedure;
SqlCommandBuilder.DeriveParameters(command);
command.Parameters["@BusinessEntityID"].Value = 6;
DeriveParameters требует дополнительного цикла обращения к базе данных при каждом вызове. При необходимости вычисляйте метаданные во время разработки, а затем явно определяйте параметры в участках кода, критичных к производительности.