始终将DBNull SqlParameter键入为int是否安全?

时间:2016-12-21 18:21:53

标签: c# sql-server ado.net

最近,我们遇到了以下问题:

简而言之:myCommand.Parameters.AddWithValue("@SomeParameter", DBNull.Value);显然"类型" DBNull参数作为nvarchar,可以隐式转换为几乎所有其他类型,但遗憾的是,不是varbinary,产生以下错误:

  

不允许从数据类型nvarchar到varbinary(max)的隐式转换。使用CONVERT函数运行此查询。

不幸的是,链接问题中建议的解决方案不适用,因为我们在数据访问库的深处使用AddWithValue,该数据访问库旨在从参数类型推断数据类型,并且不支持添加&# 34;实" SQL Server类型。

我"修复"这个问题通过明确键入DBNull参数为int来代替:

void MyImprovedAddWithValue(SqlCommand cmd, string key, object value)
{
    if (value == DBNull.Value) 
    {
        cmd.Parameters.Add(key, SqlDbType.Int).Value = DBNull.Value;
    }
    else
    {
        cmd.Parameters.AddWithValue(key, value);
    }
}

似乎可行。显然,NULL类型为int 可以隐式转换为SQL Server支持的任何其他类型。

忽略AddWithValue has some well-known shortcomings(我们完全清楚)的事实,使用这种方法有什么问题可以预料到吗? SqlParameterCollection.AddWithValue的设计师是否有充分的理由不这样做"默认情况下#34;我忽略了什么?

2 个答案:

答案 0 :(得分:1)

AddWithValue有更多问题。由于query plan cache pollution创建了NVARCHAR(X)类型的参数,其中X是值的确切长度,因此存在planar ransac问题。由于NVARCHAR(73)是与NVARCHAR(74)不同的类型,因此SQL Server查询计划缓存会被许多相同的计划污染,这些计划仅在参数类型上有所不同。另一个问题是比较中涉及VARCHAR类型的列,而NVARCHAR类型的参数导致类型转换,而不是取消对所述列上的索引的使用。

有很多理由反对AddWithValue,我从不使用它,从不推荐它,并且总是在它周围添加类型的包装。我建议你这样做。

答案 1 :(得分:1)

不,根据conversion chart(在“隐式转化”下),这并不总是安全的。 INT可以隐式转换为批量,但不能转换为DATETIMEDATETIMEOFFSETDATETIME2UNIQUEIDENTIFIER,{{1} },IMAGENTEXTTEXT,CLR UDT和XML。其中一些类型比其他类型更常见,但在实践中很容易遇到与HIERARCHYIDDATETIME2的不兼容。

没有T-SQL类型对每个其他类型都有隐式转换,因此如果您不知道目标类型,那么实际上没有好办法。在所有类型中,字符类型UNIQUEIDENTIFIERCHAR具有最隐含的转换,仅缺少VARCHARBINARY(您的情况)和使用的{{1} }}。 VARBINARYTIMESTAMP紧随其后,另外缺少已弃用的NCHAR类型。考虑到所有这些,NVARCHAR显然是默认的最佳选择,因为它可以表示所有字符串,并且仅在隐式转换为IMAGE类型时失败,NVARCHAR类型不像类型{{BINARY类型。 1}}不会转换为(即使是INT)。