最近,我们遇到了以下问题:
简而言之: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;我忽略了什么?
答案 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
可以隐式转换为批量,但不能转换为DATE
,TIME
,DATETIMEOFFSET
,DATETIME2
,UNIQUEIDENTIFIER
,{{1} },IMAGE
,NTEXT
,TEXT
,CLR UDT和XML
。其中一些类型比其他类型更常见,但在实践中很容易遇到与HIERARCHYID
和DATETIME2
的不兼容。
没有T-SQL类型对每个其他类型都有隐式转换,因此如果您不知道目标类型,那么实际上没有好办法。在所有类型中,字符类型UNIQUEIDENTIFIER
和CHAR
具有最隐含的转换,仅缺少VARCHAR
,BINARY
(您的情况)和使用的{{1} }}。 VARBINARY
和TIMESTAMP
紧随其后,另外缺少已弃用的NCHAR
类型。考虑到所有这些,NVARCHAR
显然是默认的最佳选择,因为它可以表示所有字符串,并且仅在隐式转换为IMAGE
类型时失败,NVARCHAR
类型不像类型{{BINARY
类型。 1}}不会转换为(即使是INT
)。