【问题标题】:When should "SqlDbType" and "size" be used when adding SqlCommand Parameters?添加 SqlCommand 参数时应该何时使用“SqlDbType”和“size”?
【发布时间】:2011-06-05 05:15:44
【问题描述】:

有一个相关的问题:

What's the best method to pass parameters to SQLCommand?

但我想知道不同之处是什么,以及不同方式是否存在任何问题。

我通常使用这样的结构:

using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(SQL, conn))
{
     cmd.CommandType = CommandType.Text;
     cmd.CommandTimeout = Settings.Default.reportTimeout;
     cmd.Parameters.Add("type", SqlDbType.VarChar, 4).Value = type;

     cmd.Connection.Open();

     using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
     {
         adapter.Fill(ds);
     }
      //use data                    
}

现在有几种方法可以添加 cmd 参数,我想知道哪种方法最好:

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

我认为在传递 varchars 时具有字段长度是不可取的,因为它是一个神奇的值,以后可能会在数据库中更改。它是否正确?它是否会导致以这种方式传递 varchar 的任何问题(性能或其他),我假设它默认为 varchar(max) 或数据库等效项。我很高兴这会奏效。

如果我使用上面列出的第三个或第四个选项,我更关心的部分是 SqlDbType 枚举的丢失,我根本没有提供类型。在某些情况下这不起作用我可以想象 varchar 被错误地转换为 char 或反之亦然的问题,或者可能是小数转换为金钱的问题......

就数据库而言,我想说的字段类型更改的可能性远小于长度,因此值得保留吗?

【问题讨论】:

  • 虽然没有回答您的问题,但您知道拨打SqlDataAdapter.Fill() 之前不需要打开连接,不这样做有好处吗?
  • @Rowland 好点。我确实知道,尽管这是我的代码中的一个疏忽。我想我是从我使用 SqlDataReader 而不是适配器的地方获取原始代码块(您确实需要为此打开连接吗?)。这就是顽皮的复制/粘贴编程所得到的:-)。现在在我的代码中修复。
  • 我只是想提一下,因为这是“人们可能不知道的晦涩提示”之一

标签: c# .net ado.net sqlcommand


【解决方案1】:

根据我的经验,我会确保我做这些事情:

  • 确保是您自己定义了参数的数据类型。 ADO.NET 在猜测方面做得不错,但在某些情况下,它可能非常糟糕——所以我会避免这种方法:

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

    让 ADO.NET 通过传递的值来猜测参数的类型是很棘手的,如果它因任何原因而关闭,那么跟踪和查找这些 bug 真的很棘手!想象一下当您传入 DBNull.Value 时会发生什么 - ADO.NET 应该为此选择什么数据类型?

    只要明确 - 说出你想要的类型!

  • 如果您使用字符串参数,请确保明确定义长度 - 所以我也会避免这种方法:

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

    如果您不提供长度,ADO.NET 可能会默认为某个任意值,或者作为值传入的字符串的长度,或者其他什么 - 您永远无法确定。如果您的长度与存储过程的实际期望不匹配,您可能会看到转换和其他令人不快的惊喜。所以如果你定义一个字符串,也要定义它的长度!

所以在你的情况下,唯一真正适合我的方法是这里的这个:

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

因为它 a) 明确定义要使用的数据类型,b) 明确定义字符串的长度。

【讨论】:

  • 如果你使用的是存储过程,你不能直接从SqlCommandBuilder.DeriveParameters(cmd)提供的元数据中获取参数类型吗?
  • 传入的长度应该是底层参数定义的长度吗?如果是这样,那不是违反 DRY 吗?
【解决方案2】:

通过添加类型,您的请求更有可能通过使用缓存查询计划来提高性能。

这是来自 MSDN 的引用:

参数化命令还可以提高查询执行性能,因为它们可以帮助数据库服务器准确地将传入命令与适当的缓存查询计划相匹配。

更多内容请阅读Execution Plan Caching and Reuse

【讨论】:

  • Pete 的所有选项都是参数化的,所以如果以不同的方式添加参数会影响性能,我会感到惊讶 - 您链接到的文章中肯定没有明确提及。
  • 我不同意。文章描述的是,通过尽可能准确地定义参数,它更有可能使用缓存的查询计划,然后具有更高的性能。简单参数化小节说:在 SQL Server 中,在 Transact-SQL 语句中使用参数或参数标记可以提高关系引擎将新 SQL 语句与现有的、先前编译的执行计划相匹配的能力。
猜你喜欢
  • 2011-05-26
  • 2015-08-08
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
  • 2013-09-20
相关资源
最近更新 更多