2015-03-25 3 views
4

Я написал кучу общих вспомогательных функций C# в качестве базы для своих SQL-запросов. Все параметры объекта null преобразуются в DBNull.Value. Но когда целевой столбец является varbinary, он сообщает мне, что тип string несовместим с binary, и я должен преобразовать.Почему DBNull.Value требует правильного SqlDbType?

Зачем нужен SqlDbType a DBNull.Value в C#? И есть ли общий способ обойти это?

// works for nvarchar but throws for varbinary columns 
// notice the lack of SqlDbType as I don't know it for a null object 
var param1 = new SqlParameter(); 
param1.Name = "@Param1"; 
param1.Value = DBNull.Value; 

Это нуль ... ему не нужен тип. Сервер SQL знает тип null. В SQL вы говорите [Column] IS NULL не [Column] IS TYPE NULL. Таким образом, null является нетипизированным. И целевой столбец разрешен из запроса не SqlDbType.

Я просто нахожу это очень неинтуитивным (явно набрав нули). Я интересно, если я что-то не хватает ...

код выглядит так:

SqlCommand CreateCommand(string query, params object[] arguments) { ... } 
// in here I walk the parameters and build the proper SqlParameter for them. 
// this saves me from setting up the SqlParameters by hand. 

PS: String = NVARCHAR и Binary означает VARBINARY. Серьезно ... PPS: Не интересует EF или что-нибудь подобное.

+5

Ваш вопрос не совсем ясен. Как преобразование 'string' в' binary' связано с 'DBNull.Value'? Можете ли вы показать конкретный образец кода? –

+0

Откуда? String? Введите изображение? Если это 'DBNull', это не' string'. Это еще одна история ... – DonBoitnott

+3

Также вы можете показать пример кода, который показывает, как вы это делаете? Может быть полезен контекст –

ответ

6

Если вы не указали DBType своего SqlParameter - он имеет значение по умолчанию SqlDBType.NVarchar (см. MDSN для справки).

Вот почему вы получаете исключение - ваш тип параметра - NVarchar, но целевой столбец - VarBinary.

Обратите внимание, что вы имеют установить DBType явно только потому, что, очевидно, ADO.NET не может вывести тип данных из DBNull.Value.

nullне тип - это просто absense значения, так что если я дам вам null вы не можете вывести, если это отсутствие varchar или, например, отсутствие int.

UPDATE

Я сделал некоторые эксперименты. Давайте рассмотрим простой код:

SqlCommand cmd = new SqlCommand("select * from sometable where somecolumn = @Param1"); 
cmd.Connection = _MyConnection; 

var param = new SqlParameter(); 
param.ParameterName = "@Param1"; 
param.Value = DBNull.Value; 
cmd.Parameters.Add(param); 

cmd.Connection.Open(); 
try 
{ 
    cmd.ExecuteNonQuery(); 
} 
finally 
{ 
    cmd.Connection.Close(); 
} 

Как мы можем видеть из SQL Profiler, это будет переведен на фактический запрос SQL, как:

exec sp_executesql 
    N'select * from sometable where somecolumn = @Param1', 
    N'@Param1 nvarchar(4000)', 
    @Param1=NULL 

Итак, мы, безусловно, получите исключение, если somecolumn тип данных не может неявно конвертируется из varchar только потому, что для типа данных @Param1 явно установлено значение varchar.

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

Но есть одна проблема, которая меня путает. Если мы будем выполнять не прямой запрос, но «пустышку» хранимую процедуру, имеющую varbinary в качестве параметра, скажем:

create procedure [dbo].[usp_Test] 
(
    @Param1 varbinary(max) 
) 
as 
begin 
    set nocount on 

    select null 
end 

Теперь давайте попробуем назвать это нравится:

SqlCommand cmd = new SqlCommand("dbo.usp_Test"); 
cmd.CommandType = CommandType.StoredProcedure; 
... and so on (the rest of code dealing with parameter) 

Теперь в SQL Profiler мы Здесь можно увидеть только следующее:

exec dbo.usp_Test @Param1=NULL 

И это довольно странно, поскольку это абсолютно юридический вызов без явной спецификации типа параметра. На самом деле, если мы назовем это в SQL Management Studio, мы не получим никакого исключения.

Эта часть поведения ADO.NET для меня довольно странная. Вероятно, SQL Profiler не показывает полный процесс (несмотря на то, что я включил отслеживание всех событий), я не знаю.

В любом случае - рекомендации все те же - всегда указывайте DBType вашего SqlParameter явно.

+0

В SQL, 'datatype' совершенно не имеет значения. Все зависит от целевого столбца. Тип хранится в определении таблицы не в том, что я отправляю. Это не SQLite, где любой столбец может иметь любой тип. – CodeAngry

+0

Но это не о том, что происходит в SQL. Речь идет о том, что происходит в .NET, отличном от базовых СУБД. –

+0

@roryap По-прежнему 'DBNull.Value' является специальным значением. Должно быть ясно, что это нуль и не нужен тип, поскольку он разрешен на основе целевого столбца. Это то, что я считаю глупым. Зачем вводить недостаток чего-то? Я надеялся, что я что-то упустил, и это не по дизайну. – CodeAngry

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