2016-12-21 10 views
2

В последнее время мы столкнулись следующий вопрос:Безопасно ли всегда вводить DBNull SqlParameter как int?

В двух словах: myCommand.Parameters.AddWithValue("@SomeParameter", DBNull.Value);, по-видимому «типа» Параметр, DBNull как NVARCHAR, который может быть неявно преобразован в почти все другие типы, но, к сожалению, не varbinary, что приводит к следующей ошибке:

Implicit conversion from data type nvarchar to varbinary(max) is not allowed. Use the CONVERT function to run this query.

К сожалению, решения, предложенные в связанном вопросе, не применяются, поскольку мы используем AddWithValue внутри библиотеки доступа к данным, которая предназначена для вывода типа данных из типа параметра и не поддерживает добавление «реального» типа SQL Server.

I "фиксированный" этот вопрос явным образом введя параметры DBNull в int с вместо:

void MyImprovedAddWithValue(SqlCommand cmd, string key, object value) 
{ 
    if (value == DBNull.Value) 
    { 
     cmd.Parameters.Add(key, SqlDbType.Int).Value = DBNull.Value; 
    } 
    else 
    { 
     cmd.Parameters.AddWithValue(key, value); 
    } 
} 

Это кажется работать. По-видимому, NULL, введенный как int , может быть неявным образом преобразован в любой другой тип, поддерживаемый SQL Server.

Игнорируя тот факт, что AddWithValue has some well-known shortcomings (что мы прекрасно знаем), есть ли какие-либо проблемы, ожидающие использования этого подхода? У дизайнеров SqlParameterCollection.AddWithValue есть веская причина не делать это «по умолчанию», которые я пропускаю?

+0

AddWithValue работает с DBNULL, у вас будут проблемы, когда значение == null –

+2

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

+0

Все хорошо и хорошо, когда вы создаете параметры в коде верхнего уровня, но не имеет большого смысла для фреймворка или API, который строит SqlParameters глубоко внутри слоев извлечения. –

ответ

1

Нет, это не всегда безопасно, за conversion chart (в разделе «неявные преобразования»). INT может быть неявно преобразован в партии, но не DATE, TIME, DATETIMEOFFSET, DATETIME2, UNIQUEIDENTIFIER, IMAGE, NTEXT, TEXT, XML, CLR и HIERARCHYID Пользовательские типы. Некоторые из этих типов более распространены, чем другие, но несовместимость с DATETIME2 и UNIQUEIDENTIFIER будет легко встретить на практике.

Нет типов T-SQL, которые имеют неявные преобразования для каждого другого типа, поэтому действительно нет хорошего способа сделать это, если вы не знаете тип цели.Из всех типов типы символов CHAR и VARCHAR имеют самые неявные преобразования, не имеющие только BINARY, VARBINARY (ваш случай) и гораздо менее используемых TIMESTAMP. NCHAR и NVARCHAR находятся позади, дополнительно не хватает устаревшего типа IMAGE. Имея это в виду, NVARCHAR, по-видимому, является лучшим выбором по умолчанию, поскольку он может представлять все строки и терпит неудачу только при неявном преобразовании типов BINARY, которые менее распространены, чем типы INT не конвертируется (даже для NULL) ,

+0

Ой, недостающее преобразование 'uniqueidentifier' сломало бы много кода. Благодаря! Это не то, на что я надеялся, но он полностью отвечает на вопрос. По-видимому, замена параметра буквальным «NULL» - единственный способ обойти это ... – Heinzi

1

AddWithValue имеет больше проблем. Возникает вопрос query plan cache pollution, вызванный тем, что он создает параметр типа NVARCHAR(X), где X - это точная длина значения. Так как NVARCHAR(73) отличается от типа от NVARCHAR(74), кэш плана запроса SQL Server загрязняется многими идентичными планами, которые отличаются только типом параметра. Другая проблема заключается в том, что столбец типа VARCHAR участвует в сравнении, а параметр типа NVARCHAR вызывает преобразование типов, чем дисквалифицирует использование индекса в указанном столбце.

Существует так много причин против AddWithValue, что я никогда не использую его, никогда не рекомендую его и всегда добавляю напечатал обертки вокруг него. Я предлагаю вам сделать то же самое.

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

  • Нет связанных вопросов^_^