Подтвердить что ты не робот

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

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

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

или

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

или

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Вы цитируете списки параметров для нескольких перегрузок 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 являются просто удобством для установки свойств экземпляра. Они сокращают код, оказывая незначительное влияние на производительность: конструктор может обходить методы установки и работать непосредственно с закрытыми членами. Если будет какая-то разница, ее будет не много.

Что мне делать?

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

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

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

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

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


2008 год был давным-давно

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

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

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

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

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

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

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

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


2019 год, и мир снова движется

Linq2Sql недоступен в dotnet Core, поэтому я использую Dapper. Проблема [N] VARCHAR все еще остается проблемой, но она больше не скрыта. Я полагаю, что можно также использовать ADO, чтобы все прошло в этом направлении.

Ответ 3

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

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

Ответ 4

Я использовал ваш вариант 1:

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

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

Ответ 5

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