Когда следует использовать «SqlDbType» и «размер» при добавлении параметров SqlCommand? - PullRequest
41 голосов
/ 07 января 2011

С этим связан вопрос:

Какой лучший способ передачи параметров в 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, и мне интересно, какой из них лучше:

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 или наоборот, или, возможно, проблемы с десятичной дробью в деньги ...

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

Ответы [ 2 ]

55 голосов
/ 07 января 2011

По своему опыту я бы сделал следующее:

  • убедитесь, что именно вы определяете тип данных для параметра.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";

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

6 голосов
/ 07 января 2011

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

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

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

Подробнее читайте в Кэширование и повторное использование плана выполнения .

...