Как лучше всего передать параметры в 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";
Похоже, что первый из них может быть каким-то образом "лучше" либо с точки зрения производительности, либо с точки зрения проверки ошибок. Но я хотел бы знать более определенно.
5 ответов:
Вы также можете использовать
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
перегрузка это занимает aString
и ASqlDbType
значение перечисления, где передача целое число со строкой может быть интерпретируется как либо значение параметра или соответствующееSqlDbType
значение. ИспользоватьAddWithValue
всякий раз, когда вы хотите добавить параметр указав его название и значение.Перегрузки конструктора для класса
SqlParameter
являются простыми удобствами для установки свойств экземпляра. Они сокращают код, оказывая незначительное влияние на производительность: конструктор может обойти методы setter и работать непосредственно с закрытыми членами. Если и есть разница, то не очень большая.Что мне делать?
Обратите внимание на следующее (от MSDN)
Для двунаправленного и выходного сигналов параметры и возвращаемые значения, вы необходимо установить значение из
Size
. Это не требуется для входных параметров, и если явно не задано, то значение равно выводится из фактического размера указанный параметр, когда a выполнении инструкции.Тип по умолчанию-input. Однако, если вы позволяете размер выводиться таким образом, и вы повторно используете объект parameter в цикле (вы сказали, что вас беспокоит производительность) , то размер будет установлен первым значением, а любые последующие значения, которые длиннее, будут быть обрезанным. Очевидно, что это важно только для значений переменной длины, таких как строки.
Если вы повторно передаете один и тот же логический параметр в цикле, я рекомендую вам создать объект SqlParameter вне цикла и соответствующим образом его размерить. Завышение размеров варчара безвредно, поэтому, если это Пита, чтобы получить точный максимум, просто установите его больше, чем вы когда-либо ожидали, что колонна будет. Поскольку вы перерабатываете объект, а не создаете новый для каждой итерации, память потребление в течение всего цикла, скорее всего, упадет , даже если вы немного взволнованы чрезмерным размером.
По правде говоря, пока вы не обработаете тысячи вызовов, ничто из этого не будет иметь большого значения.AddWithValue
создает новый объект, обходя проблему калибровки. Это коротко, мило и легко понять. Если вы перебираете тысячи, используйте мой подход. Если это не так, используйтеAddWithValue
, чтобы ваш код был простым и легким в обслуживании.
2008 год был очень долгим. назад За годы, прошедшие с тех пор, как я написал это, мир изменился. Есть новые виды дат, и есть также проблема, которая не приходила мне в голову, пока недавняя проблема с датами не заставила меня задуматься о последствиях расширения. Расширение и сужение, для тех, кто не знаком с терминами, являются качествами преобразования типов данных. Если вы назначаете int двойнику, нет никакой потери точности, потому что double "шире". Это всегда безопасно, так что преобразование-это автоматический. Вот почему вы можете назначить int двойнику, но идя другим путем, вы должны сделать явное приведение-double к int-это сужающее преобразование с потенциальной потерей точности.Это может относиться к строкам: NVARCHAR шире VARCHAR, поэтому вы можете назначить VARCHAR NVARCHAR, но движение в другую сторону требует приведения. Сравнение работает, потому что VARCHAR неявно расширяется до NVARCHAR, но это будет мешать использованию индексов!
Строки C# являются Unicode, поэтому AddWithValue создаст параметр NVARCHAR. На другом конце значения столбца VARCHAR расширяются до NVARCHAR для сравнения. Это не останавливает выполнение запроса, но предотвращает использование индексов. Это плохо.
Что вы можете сделать об этом? У вас есть два возможных решения.
- явно введите параметр. Это означает, что больше нет AddWithValue
- измените все типы строковых столбцов на NVARCHAR.
Бросать ВАРЧАРА, вероятно, лучше всего идея. Это простое изменение с предсказуемыми последствиями, и оно улучшает вашу историю локализации. Однако у вас может не быть такого варианта.
В эти дни я не делаю много прямых ADO.NET. Linq2Sql теперь мое оружие выбора, и акт написания этого обновления оставил меня в недоумении, как он справляется с этой проблемой. У меня внезапно возникло жгучее желание очистить свои базы данных от ВАРЧАРА.
Я бы сказал #1 наверняка. Но, однако Microsoft делает это в блоке Приложения доступа к данным в библиотеке enterprise library лучше всего, особенно для SQL server:
Я использовал ваш вариант 1:
Cmd.Параметры.Добавить ("@Name", SqlDbType.Варчар, 20).Value = "Bob";
Который работал нормально, но затем я начал использовать .AddWithValue, и это так просто, как он получает. Это не вызвало у меня проблем после многих тысяч применений. Заметьте, я почти всегда передаю свои классы частным переменным, поэтому мне не нужно так сильно беспокоиться о неявном преобразовании типов.