Command.CommandText
= ProcedimientoAlmacenado
Параметры также должны иметь имена. Содержит ли массив Parametros объекты SqlParameter или общие объекты C #?
Если параметры являются общими объектами C #, лучше передать в словарь имен и значений:
protected void EjecutarGuardar(string ProcedimientoAlmacenado,
Dictionary<string, object> Parametros)
{
using (SqlConnection Connection = new SqlConnection(...))
{
Connection.Open();
SqlCommand Command = Connection.CreateCommand()
Command.CommandText = ProcedimientoAlmacenado;
Command.Connection = Connection;
Command.CommandType = CommandType.StoredProcedure;
foreach (string name in Parametros.Keys)
{
Command.Parameters.AddWithValue(name, Parametros[name] ?? DBNull.Value);
}
Command.ExecuteNonQuery();
}
}
Это быстрый и грязный подход. Обратите внимание, что при таком подходе обычно возникают проблемы, потому что AddWithValue будет передавать параметр типа NVARCHAR для строки, а не VARCHAR, а в случае специального SQL это может вызвать проблемы с индексной SARG-способностью для столбцов VARCHAR (поскольку преобразование будет всегда из VARCHAR в NVARCHAR, а не наоборот). Однако с хранимыми процедурами нет такой проблемы, потому что процедуры имеют параметры типов, и, следовательно, принудительное принуждение происходит с VARCHAR, если процедура была создана с параметром типа VARCHAR.
У вас также будут проблемы с передачей NULL-параметров, поэтому вам нужно сделать что-то вроде, параметр должен быть DBNull.Value
, а не null
:
Command.Parameters.AddWithValue(name, Parametros[name] ?? DBNull.Value);
В высокопроизводительных системах этот подход также излишне загрязняет кэш выполнения, потому что AddWithValue будет передавать параметры типа NVARCHAR(<exact length of the string>)
, а не NVARCHAR(<length of the database type>)
. Таким образом, Paramaters.AddWithValue("@name", "John")
и Parameters.AddwithValue("@name", "Doe")
создадут два отдельных плана в кэше, потому что один вызывается с параметром типа NVARCHAR (4), другой - с параметром NVARCHAR (3), и они рассматриваются в кэше плана SQL как разных типов . Это не проблема для простых проектов, но для более сложных и высокопроизводительных проектов рекомендуется явно задавать типы параметров.
Я бы порекомендовал избегать такого рода универсальных процедур «один размер подходит всем» и вместо этого написать слой доступа к данным с явной оболочкой C # для каждой процедуры базы данных с соответствующими типами параметров. Строго типизированный набор данных может на самом деле сделать это, другой альтернативой (мой любимый и то, что я всегда использую) является генерация всего убийцы доступа к данным из файла XML с использованием таблицы стилей XSLT, которая создает оболочки C #. Разумеется, исходный XML извлекается из метаданных базы данных.