我想用.NET运行参数化SQL。但是当我使用AddWithValue()
时,生成的命令不起作用。
SqlCommand cmd = new SqlCommand("SELECT * FROM table WHERE table.name = @A")
cmd.Parameters.AddWithValue("@A", "A string");
生成此sql命令:
exec sp_executesql N'SELECT * FROM table WHERE table.name = @A',N'@A nvarchar(10)',@A=N'''A string'''
但是该命令不返回任何值,而以下命令返回我想要的值(即匹配一行):
SELECT * FROM table WHERE table.name = 'A String'
第二个查询完成了我的预期,我希望两个查询都返回相同的结果。
我在代码中做错了什么?
答案 0 :(得分:5)
Profiler没有说谎,它说您传入的值为@A=A string
的参数。这与A String
不同。这意味着您可能正在添加如下参数:
cmd.Parameters.AddWithValue("@A", "@A=A string");
<强>更新强>
修好帖子后。测试和sql_executesql
实际上仍然不同。这次差异很微妙:参数是Unicode类型!这意味着查询必须执行从Name列类型(可能是Varchar)到Unicode(Nvarchar)的转换。此转换将考虑您对列的排序规则,并且可能会导致其他内容超出预期。作为副作用,它还使查询不具有SARG能力(即使Name具有索引,也将扫描整个表!)。 AddWithValue创建NVARCHAR类型参数的事实是一个已知的陷阱,这就是为什么大多数退伍军人都会避免这种情况。它还创建类型长度的参数,与参数长度完全相同(即NVARCHAR(10)),因为查询计划依赖于参数 types ,而NVARCHAR(10)是不同的类型< / em>比NVARCHAR(11),这导致糟糕的计划缓存重用,更高的编译时间和缓存压缩。这两个问题的解决方案是在CLR中使用显式创建的参数,并控制参数SqlDbType和length(即始终使用列长度)。我知道的“快速发展”不如AddWithValue
,但不幸的是,现在这是ADO.Net的事态。