2011-01-07 2 views
35

Существует связанный с этим вопрос к этому:Когда следует использовать «SqlDbType» и «размер» при добавлении параметров SqlCommand?

What's the best method to pass parameters to SQLCommand?

Но я хотел бы знать, каковы различия и если есть какие-либо проблемы с различными способами.

Я обычно использую структуру что-то вроде этого:

using (SqlConnection conn = new SqlConnection(connectionString)) 
using (SqlCommand cmd = new SqlCommand(SQL, conn)) 
{ 
    cmd.CommandType = CommandType.Text; 
    cmd.CommandTimeout = Settings.Default.reportTimeout; 
    cmd.Parameters.Add("type", SqlDbType.VarChar, 4).Value = type; 

    cmd.Connection.Open(); 

    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd)) 
    { 
     adapter.Fill(ds); 
    } 
     //use data      
} 

В настоящее время существует несколько способов добавления ЦМД параметров, и я гадаю, который лучше всего:

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

Имея длину из поле в передаче varchars, я предполагаю, не является предпочтительным, поскольку это волшебное значение, которое может быть изменено позже в базе данных. Это верно? Это вызывает любую проблему, передающую varchar таким образом (производительность или другое), я предполагаю, что по умолчанию используется varchar (max) или эквивалент базы данных. Я достаточно рад, что это сработает.

Часть, которая касается меня больше, является потерей перечисления SqlDbType, если я использую третий или четвертый варианты, перечисленные выше. Я вообще не предоставляю тип. Есть случаи, когда это не сработает, я могу представить, что проблемы с varchar некорректно передаются на char или наоборот или, возможно, с десятичным делением на деньги ....

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

+3

Не отвечая на свой вопрос, вы знаете, что вам не нужно открывать соединение до вызова 'SqlDataAdapter.Fill()', и есть ли в этом преимущества? –

+0

@ Rowland хороший пункт. Я действительно знал, что, хотя это был надзор в моем коде. Я думаю, что я взял исходный блок кода откуда-то, что я использовал SqlDataReader, а не адаптер (вам нужно открыть соединение для этого?). Это то, что вы получаете за непослушные программы копирования/вставки :-). Исправлено в моем коде. – PeteT

+0

просто подумал, что я упоминал об этом, так как это один из тех «неясных советов, которые люди могут не знать о» –

ответ

49

В моем опыте, я бы убедиться, что я это делаю:

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

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

    Позволить ADO.NET угадать тип параметра, передаваемое значение сложно, и если это по какой-либо причине, это действительно сложные ошибки для отслеживания и поиска! Представьте, что происходит, когда вы проходите в DBNull.Value - какой тип данных должен выбрать ADO.NET?

    Просто напишите - скажите, какой тип вы хотите!

  • если вы используете параметры строки, убедитесь, что явно определить длину - так что я бы избежать этого метода тоже:

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

    Если вы не предоставите длину, ADO. NET может по умолчанию использовать какое-либо произвольное значение, или длину строки, переданной как значение, или что-то еще - вы никогда не уверены. И если ваша длина не соответствует тому, что действительно ожидает сохраненная программа, вы можете увидеть конверсию и другие неприятные сюрпризы. Поэтому, если вы определяете строку, определите ее длину тоже!

Так что в вашем случае, единственный подход, который действительно работает для меня это один здесь:

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

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

+0

Если вы используете хранимую процедуру, не можете ли вы просто получить тип параметра из метаданных, предоставленных SqlCommandBuilder.DeriveParameters (CMD)? – devinbost

+0

Должна ли длина проходить в соответствии с определением базового параметра? И если так, разве это не нарушает DRY? – tbone

4

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

Вот цитата из MSDN:

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

Подробнее читайте в Execution Plan Caching and Reuse.

+0

Все параметры Pete параметризированы, поэтому я был бы удивлен, если добавление параметров по-разному влияет на производительность - это, безусловно, явно не упоминается в статье, к которой вы привязались. –

+4

Я не согласен. Что описывается в статье, так это то, что, определяя параметр как можно точнее, он более вероятен, что план кешированных запросов, который будет использоваться, а затем с более высокой производительностью. В разделе «Простая параметризация» говорится следующее: в SQL Server использование параметров или маркеров параметров в операциях Transact-SQL повышает способность реляционного движка соответствовать новым SQL-операторам с существующими ранее скомпилированными планами выполнения. – StefanE

Смежные вопросы