【问题标题】:Why does the SqlParameter name/value constructor treat 0 as null?为什么SqlParameter名称/值构造函数将0视为null?
【发布时间】:2012-01-11 05:48:54
【问题描述】:

我在一段代码中观察到一个奇怪的问题,即即席 SQL 查询没有产生预期的输出,即使它的参数与数据源中的记录匹配。我决定在即时窗口中输入以下测试表达式:

new SqlParameter("Test", 0).Value

这给出了null 的结果,这让我摸不着头脑。 SqlParameter 构造函数似乎将零视为空值。以下代码产生正确的结果:

SqlParameter testParam = new SqlParameter();
testParam.ParameterName = "Test";
testParam.Value = 0;
// subsequent inspection shows that the Value property is still 0

谁能解释这种行为?是不是故意的?如果是这样,那可能是相当危险的......

【问题讨论】:

标签: c# sql-server ado.net sqlparameter


【解决方案1】:

正如documentation 中针对该构造函数所述:

当您在 value 参数中指定 Object 时,SqlDbType 是从 Object 的 Microsoft .NET Framework 类型推断出来的。

使用SqlParameter 构造函数的此重载来指定整数参数值时要小心。由于此重载采用 Object 类型的值,因此当值为零时,您必须将整数值转换为 Object 类型,如以下 C# 示例所示。

Parameter = new SqlParameter("@pname", (object)0);

如果您不执行此转换,编译器会假定您正在尝试调用 SqlParameter (string, SqlDbType) 构造函数重载。

您只是调用了与您的情况不同的构造函数。

原因是 C# 允许从整数文字 0 到枚举类型(它们只是下面的整数类型)的 隐式 转换,而这种隐式转换会导致 (string, SqlDbType) 构造函数比将int 转换为object(string, object) 构造函数所需的装箱转换更适合重载解析。

当您传递int 变量 时,这绝不会成为问题,即使该变量的值是0(因为它不是零字面量)或任何其他表达式类型为int。如果您如上所示将int 显式转换为object,也不会发生这种情况,因为只有一个匹配的重载。

【讨论】:

  • 我遇到了这个问题并尝试了一个不起作用的不同解决方案:为什么我尝试的 Parameter = new SqlParameter("@pname", (int)0); 不起作用时建议的 Parameter = new SqlParameter("@pname", Convert.ToInt32(0)); 起作用?
  • @mortb,您必须为此查阅语言规范,但我的猜测是,重载解析在第一种情况下会关心确切的类型,但在第二种情况下可能允许枚举,因为您' 仍在传递int 类型的文字。
  • 我找到了原因:stackoverflow.com/questions/3153841/… 文字 0 将始终被评估为匹配枚举的类型,而其他数字则不会。似乎有点晦涩...
  • 引用的示例有问题:Convert.ToInt32(0) 不会更改选择的重载。代码应该是new SqlParameter("@pname", (object)0);
  • @Steven:如果我错了,请纠正我,但只有 literal 0 可以隐式转换为任何枚举类型。因此,返回int 的方法调用很好,可以选择另一个重载。不可否认,自从我查看规范以来已经有几个月了,但是 afaik 它就是这样工作的。
【解决方案2】:

在传递/添加参数时使用类型化数据是一种很好的做法。

您可以通过以下方式完成以下任务:

对于字符串/varchar 类型的数据:

SqlParameter pVarchar = new SqlParameter
                    {
                        ParameterName = "Test",
                        SqlDbType = System.Data.SqlDbType.VarChar,
                        Value = string.Empty,
                    };

对于 int 类型的数据:

SqlParameter pInt = new SqlParameter
                    {
                        ParameterName = "Test",
                        SqlDbType = System.Data.SqlDbType.Int,
                        Value = 0,
                    };

您可以根据您使用的数据更改SqlDbType的值。

【讨论】:

  • 虽然通常很有帮助,但从技术上讲,这并不是问题的答案。因此它应该是一个评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
  • 2019-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多