我编写了一堆通用的C#辅助函数作为我的SQL查询的基础.所有null对象参数都转换为a DBNull.Value.但是当目标列是a时varbinary,它告诉我该string类型与该类型不兼容,binary我必须转换.
为什么我需要SqlDbType一个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;
Run Code Online (Sandbox Code Playgroud)
它是一个空的...它不需要任何类型.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.
Run Code Online (Sandbox Code Playgroud)
PS:String = NVarChar和Binary表示VarBinary.说真的...... PPS:对EF或类似的东西不感兴趣.
如果不设置DBType你的SqlParameter明确-它有默认值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();
}
Run Code Online (Sandbox Code Playgroud)
正如我们从SQL Profiler中看到的,这将被转换为实际的SQL查询:
exec sp_executesql
N'select * from sometable where somecolumn = @Param1',
N'@Param1 nvarchar(4000)',
@Param1=NULL
Run Code Online (Sandbox Code Playgroud)
所以在这里,如果somecolumn数据类型无法隐式转换,varchar只是因为@Param1数据类型被显式设置为,我们肯定会得到异常varchar.
初看起来 - 这可以是足够好的解释,对吧?
但有一个问题令我感到困惑.如果我们不执行直接查询,而是执行具有varbinaryas参数的"虚拟"存储过程,那么让我们说:
create procedure [dbo].[usp_Test]
(
@Param1 varbinary(max)
)
as
begin
set nocount on
select null
end
Run Code Online (Sandbox Code Playgroud)
现在让我们试着把它称为:
SqlCommand cmd = new SqlCommand("dbo.usp_Test");
cmd.CommandType = CommandType.StoredProcedure;
... and so on (the rest of code dealing with parameter)
Run Code Online (Sandbox Code Playgroud)
现在在SQL Profiler中我们将看到这样:
exec dbo.usp_Test @Param1=NULL
Run Code Online (Sandbox Code Playgroud)
这很奇怪,因为如果没有明确规范参数类型,这绝对是合法的.实际上,如果我们在SQL Management Studio中调用它 - 我们不会得到任何异常.
这部分ADO.NET行为对我来说很奇怪.可能SQL Profiler没有显示完整的过程(尽管事实上我打开了所有事件跟踪),我不知道.
反正-建议仍然是相同的-总是指定DBType你的SqlParameter明确.