为什么DBNull.Value需要正确的SqlDbType?

时间:2015-03-25 11:42:44

标签: c# sql-server

我已经编写了一堆通用的C#辅助函数作为我的SQL查询的基础。所有null个对象参数都转换为DBNull.Value。但是当目标列为varbinary时,它会告诉我string类型与binary类型不兼容,我必须转换。

为什么我需要在C#中SqlDbType DBNull.Value并且有什么通用方法可以解决这个问题吗?

// 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或类似内容不感兴趣。

1 个答案:

答案 0 :(得分:6)

如果您未明确设置DBType的{​​{1}},则其默认值为SqlParameter(请参阅MDSN以供参考)。

这就是您获得异常的原因 - 您的参数类型为SqlDBType.NVarchar,但目标列为NVarchar

请注意,您明确设置VarBinary,因为显然ADO.NET无法从DBType推断出数据类型。

DBNull.Value 不是类型 - 它只是缺少价值,所以如果我给你null你就无法推断如果缺少null,或者缺少varchar

<强>更新

我做了一些实验。让我们运行简单的代码:

int

正如我们从SQL Profiler中看到的,这将被转换为实际的SQL查询:

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();
}

所以,如果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

现在在SQL Profiler中我们将看到:

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

这很奇怪,因为如果没有明确规定参数类型,它绝对是合法的。实际上,如果我们在SQL Management Studio中调用它 - 我们不会得到任何异常。

这部分ADO.NET行为对我来说很奇怪。可能SQL Profiler没有显示完整的过程(尽管事实上我打开了所有事件跟踪),我不知道。

无论如何 - 建议仍然相同 - 始终明确指定exec dbo.usp_Test @Param1=NULL 的{​​{1}}。