将参数传递给SQLCommand的最佳方法是什么?

时间:2008-11-16 00:56:13

标签: .net sql-server ado.net sqlcommand

将参数传递给SQLCommand的最佳方法是什么?你可以这样做:

cmd.Parameters.Add("@Name", SqlDbType.VarChar, 20).Value = "Bob";

cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = "Bob";

cmd.Parameters.Add("@Name").Value = "Bob";

似乎第一个可能在某种程度上“更好”,无论是性能还是错误检查。但我想更清楚地知道。

5 个答案:

答案 0 :(得分:58)

那里发生了什么?

引用Add的多个重载的参数列表。这些是直接对应于SqlParameter类的构造函数重载的便捷方法。它们本质上构造参数对象,使用任何构造函数与您调用的方便方法具有相同的签名,然后像这样调用SqlParameterCollection.Add(SqlParameter)

SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);

AddWithValue类似但更方便,也设置了值。然而,它实际上是为解决框架缺陷而引入的。引用MSDN,

  

Add的重载需要a   字符串和对象已弃用   因为可能含糊不清   SqlParameterCollection.Add超载   需要StringSqlDbType   通过a的枚举值   字符串的整数可以是   被解释为是   参数值或相应的   SqlDbType值。AddWithValue使用SqlParameter   每当你想添加一个参数   通过指定其名称和值。

Size类的构造函数重载仅仅是设置实例属性的便利。它们缩短了代码,对性能产生了微不足道的影响:构造函数可以绕过setter方法并直接在私有成员上运行。如果存在差异则不会太多。

我该怎么办?

请注意以下内容(来自MSDN)

  

用于双向和输出   参数和返回值,你   必须设置AddWithValue的值。这是   输入参数不需要,和   如果没有明确设置,则值为   从实际大小推断出来   a时指定的参数   参数化语句被执行。

默认类型是输入。但是,如果您允许像这样推断大小并在循环中回收参数对象(您确实说您关注性能),那么大小将由第一个值设置,任何后续更长的值将是裁剪。显然,这对于诸如字符串之类的可变长度值是重要的。

如果在循环中重复传递相同的逻辑参数,我建议您在循环外创建一个SqlParameter对象并适当调整大小。过大的varchar是无害的,所以如果它是一个PITA来获得确切的最大值,只需将它设置得比你预期的那样大。因为您正在回收对象而不是为每次迭代创建一个新对象,所以即使您对超大尺寸感到有些兴奋,在循环持续时间内的内存消耗也可能掉落

说实话,除非你处理成千上万的电话,否则这些都不会产生太大的影响。 AddWithValue创建一个新对象,回避了大小调整问题。它简短,甜美,易于理解。如果你循环数千,请使用我的方法。如果不这样做,请使用{{1}}来保持代码简单易用。


2008很久以前

自从我写这篇文章以来,这个世界已经发生了变化。有新的日期,并且在最近的日期问题让我想到扩大的影响之前,还有一个问题没有出现在我脑海中。

对于那些不熟悉这些术语的人来说,扩大和缩小是数据类型转换的品质。如果为double分配int,则不会损失精度,因为double是“更宽”的。这样做总是安全的,因此转换是自动的。这就是为什么你可以将一个int分配给一个double但是另一个方法你需要进行一个显式的转换 - double to int是一个缩小的转换,可能会导致精度损失。

这可以应用于字符串:NVARCHAR比VARCHAR宽,因此您可以将VARCHAR分配给NVARCHAR,但是以另一种方式需要转换。比较有效,因为VARCHAR隐式扩展到NVARCHAR,,但这会干扰索引的使用!

C#字符串是Unicode,因此AddWithValue将生成NVARCHAR参数。另一方面,VARCHAR列值扩展到NVARCHAR以进行比较。这不会停止查询执行,但会阻止使用索引。这很糟糕。

你能做些什么?您有两种可能的解决方案。

  • 显式输入参数。这意味着不再有AddWithValue
  • 将所有字符串列类型更改为NVARCHAR。

Ditching VARCHAR可能是最好的主意。这是一个简单的变化,具有可预测的后果,它可以改善您的本地化故事。但是,您可能没有这个选项。

这几天我没有做很多直接的ADO.NET。 Linq2Sql现在是我的首选武器,编写此更新的行为让我想知道它是如何处理这个问题的。我突然想要清除我的VARCHAR数据库。

答案 1 :(得分:49)

您也可以使用AddWithValue(),但要注意隐式类型转换错误的可能性。

cmd.Parameters.AddWithValue("@Name", "Bob");

答案 2 :(得分:4)

我肯定会说#1。但是,微软在企业库中的数据访问应用程序块中是最好的,特别是SQL服务器:

http://msdn.microsoft.com/en-us/library/dd203144.aspx

答案 3 :(得分:3)

我曾经使用你的选项1:

  

cmd.Parameters.Add(“@ Name”,SqlDbType.VarChar,20).Value =“Bob”;

工作正常,但后来我开始使用.AddWithValue,它就像它得到的一样简单。经过数千次使用后,它并没有给我带来麻烦。请注意,我几乎总是传递我的类私有变量,所以我不必担心隐式类型转换。

答案 4 :(得分:2)

这取决于您的申请。我实际上喜欢2,因为如果我改变存储的proc参数的长度,我不会改变我的DAO。那只是我。我不知道是否有任何表现处罚或任何事情。