Какой лучший способ передать параметры в SQLCommand?

StackOverflow https://stackoverflow.com/questions/293311

Вопрос

Какой лучший способ передать параметры в SQLCommand?Ты можешь сделать:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob";

или

cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob";

или

cmd.Parameters.Add("@Name").Value = "Bob";

Кажется, что первый может быть каким-то «лучше» либо с точки зрения производительности, либо с точки зрения проверки ошибок.Но хотелось бы узнать более определенно.

Это было полезно?

Решение

Вы также можете использовать AddWithValue(), но помните о возможности неправильного неявного преобразования типов.

cmd.Parameters.AddWithValue("@Name", "Bob");

Другие советы

Что там происходит?

Вы цитируете списки параметров для нескольких перегрузок Add.Это удобные методы, которые напрямую соответствуют перегрузкам конструктора для SqlParameter сорт.По сути, они создают объект параметра, используя любой конструктор, имеющий ту же сигнатуру, что и удобный метод, который вы вызвали, а затем вызывают SqlParameterCollection.Add(SqlParameter) так:

SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);

AddWithValue аналогично, но еще больше повышает удобство, а также устанавливает значение.Однако на самом деле он был введен для устранения недостатка фреймворка.Цитируя MSDN,

Перегрузка Add Это требует строки, и объект устарел из -за возможной неоднозначности с SqlParameterCollection.Add перегрузка, которая принимает String и SqlDbTypeЗначение перечисления, при котором передача целого числа с помощью строки может быть интерпретировано как значение параметра или соответствующее SqlDbType ценить.Использовать AddWithValueВсякий раз, когда вы хотите добавить параметр, указав его имя и значение.

Конструктор перегружается для SqlParameter class — это всего лишь удобство для установки свойств экземпляра.Они сокращают код, оказывая незначительное влияние на производительность:конструктор может обходить методы установки и работать непосредственно с закрытыми членами.Если и будет разница, то незначительная.

Что я должен делать?

Обратите внимание на следующее (из MSDN)

Для двунаправленных и выходных параметров и возвращаемых значений, необходимо установить значение Size.Это не требуется для входных параметров, и если не установлено явно, значение выводится из фактического размера указанного параметра при выполнении параметризованного оператора.

Тип по умолчанию — входной.Однако, если вы позволите определить размер таким образом и перезапустите объект параметра в цикле (вы сказали, что вас беспокоит производительность), тогда размер будет установлен по первому значению, а любые последующие значения, которые будут длиннее, будут обрезано.Очевидно, это важно только для значений переменной длины, таких как строки.

Если вы повторно передаете один и тот же логический параметр в цикле, я рекомендую вам создать объект SqlParameter вне цикла и соответствующим образом изменить его размер.Превышение размера varchar безвредно, поэтому, если это PITA, чтобы получить точный максимум, просто установите его больше, чем вы когда-либо ожидали от столбца.Поскольку вы перерабатываете объект, а не создаете новый для каждой итерации, потребление памяти в течение цикла, скорее всего, будет уронить даже если вас немного взволновал большой размер.

По правде говоря, если вы не обработаете тысячи звонков, все это не будет иметь большого значения. AddWithValue создает новый объект, обходя проблему размера.Это коротко, мило и легко понять.Если вы перебираете тысячи, используйте мой подход.Если вы этого не сделаете, используйте AddWithValue чтобы ваш код был простым и легким в обслуживании.


2008 год был очень давно

За годы, прошедшие с тех пор, как я написал это, мир изменился.Появились новые виды дат, а также есть проблема, которая не приходила мне в голову, пока недавняя проблема с датами не заставила меня задуматься о последствиях расширения.

Для тех, кто не знаком с этими терминами, расширение и сужение — это качества преобразования типов данных.Если вы присвоите int двойному значению, потеря точности не произойдет, поскольку double «шире».Это всегда безопасно, поэтому преобразование происходит автоматически.Вот почему вы можете присвоить int типу double, но в противном случае вам придется выполнить явное приведение типа double к int — это сужающее преобразование с потенциальной потерей точности.

Это может относиться к строкам:NVARCHAR шире, чем VARCHAR, поэтому вы можете присвоить VARCHAR NVARCHAR, но в противном случае потребуется приведение типов.Сравнение работает, потому что VARCHAR неявно расширяется до NVARCHAR. но это помешает использованию индексов!

Строки C# имеют кодировку Unicode, поэтому AddWithValue создаст параметр NVARCHAR.С другой стороны, значения столбца VARCHAR расширяются до NVARCHAR для сравнения.Это не останавливает выполнение запроса, но предотвращает использование индексов.Это плохо.

Что вы можете с этим поделать?У вас есть два возможных решения.

  • Явно введите параметр.Это означает, что AddWithValue больше не требуется.
  • Измените все типы строковых столбцов на NVARCHAR.

Отказ от VARCHAR, вероятно, лучшая идея.Это простое изменение с предсказуемыми последствиями, которое улучшает вашу историю локализации.Однако у вас может не быть этой опции.

Сейчас я нечасто использую ADO.NET напрямую.Linq2Sql теперь является моим любимым оружием, и сам процесс написания этого обновления заставил меня задуматься, как он решает эту проблему.У меня внезапно возникло жгучее желание очистить мои базы данных от VARCHAR.

Я бы точно сказал №1.Но, как бы Microsoft ни делала это в блоке приложений доступа к данным в корпоративной библиотеке, лучше всего, особенно для SQL-сервера:

http://msdn.microsoft.com/en-us/library/dd203144.aspx

Раньше я использовал ваш вариант 1:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Боб";

это сработало нормально, но потом я начал использовать .AddWithValue, и это настолько просто, насколько это возможно.Это не вызвало у меня проблем после многих тысяч использований.Имейте в виду, я почти всегда передаю своим классам частные переменные, поэтому мне не нужно особо беспокоиться о неявном преобразовании типов.

Это зависит от вашего приложения.На самом деле мне нравится 2, потому что мне не нравится менять свой DAO, если я меняю длину сохраненного параметра процедуры.Хотя это только я.Я не знаю, есть ли какие-либо штрафы за производительность или что-то в этом роде.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top