我已经编写了一堆通用的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或类似内容不感兴趣。
答案 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}}。