c# – 为什么DBNull.Value需要一个合适的SqlDbType?

我编写了一堆通用的C#辅助函数作为我的SQL查询的基础.所有null对象参数都转换为DBNull.Value.但是当目标列是varbinary时,它告诉我字符串类型与二进制类型不兼容,我必须转换.为什么我需要在C#中使用SqlDbType DBNull...

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

为什么我需要在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或类似的东西不感兴趣.

解决方法:

如果您没有显式设置SqlParameter的DBType – 它具有默认值SqlDBType.NVarchar(请参阅MDSN以供参考).

这就是你得到异常的原因 – 你的参数类型是NVarchar,但目标列是VarBinary.

请注意,您必须明确设置DBType,因为显然ADO.NET无法从DBNull.Value中推断出数据类型.

null不是一个类型 – 它只是缺少值,所以如果我给你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没有显示完整的过程(尽管事实上我打开了所有事件跟踪),我不知道.

无论如何 – 建议仍然相同 – 始终明确指定SqlParameter的DBType.

本文标题为:c# – 为什么DBNull.Value需要一个合适的SqlDbType?

基础教程推荐