【问题标题】:SqlParameter "disappears" when assigned a value of null?赋值 null 时,SqlParameter“消失”?
【发布时间】:2019-05-08 22:52:44
【问题描述】:

我最近偶然发现了以下问题:

null 分配给SqlParameter 的Value 属性似乎会导致从查询中省略该参数,而不是传递NULL。当存储过程没有参数的默认值时,这会导致潜在的误导性错误消息。

我有一个数据库表,其中有一列接受NULL

USE [TheDatabase]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TheTable](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [TheValue] [varchar](50) NULL,
 CONSTRAINT [PK_TheTable] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

该表是使用存储过程填充的。请注意,以列为目标的参数没有指定默认值。

USE [TheDatabase]
GO

CREATE PROCEDURE TheStoredProcedure
    @TheValue varchar(50)
AS
BEGIN
    INSERT INTO TheTable (TheValue) VALUES (@TheValue);
END
GO

使用值和NULL执行存储过程都可以正常工作:

USE [TheDatabase]
GO

EXEC [dbo].[TheStoredProcedure] @TheValue = 'A string for Algernon'
GO

EXEC [dbo].[TheStoredProcedure] @TheValue = NULL
GO

我运行以下代码:

using System;
using System.Data;
using System.Data.SqlClient;

class Program
{
    static void Main(string[] args)
    {
        ExecuteStoredProcedure("A string for Algernon");

        ExecuteStoredProcedure(DBNull.Value);

        ExecuteStoredProcedure(null);

        Console.ReadKey();
    }

    private static void ExecuteStoredProcedure(object value)
    {
        using (var connection = new SqlConnection("Server=TheServer;Database=TheDatabase;Persist Security Info=False;Integrated Security=true;"))
        {
            connection.Open();
            using (var sqlCommand = new SqlCommand("TheStoredProcedure", connection) {CommandType = CommandType.StoredProcedure})
            {
                sqlCommand.Parameters.Add(new SqlParameter("@TheValue", SqlDbType.VarChar, 50) {Value = value});

                try
                {
                    sqlCommand.ExecuteNonQuery();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }
        }

        Console.WriteLine(DateTime.Now);
    }
}

前两个方法调用运行良好:第一个将字符串添加到表中,第二个添加NULL,但使用null 调用ExecuteStoredProcedure() 会导致以下错误:

System.Data.SqlClient.SqlException (0x80131904):过程或函数“TheStoredProcedure”需要参数“@TheValue”,但未提供。

从文档看来,当您希望在存储过程中使用参数的默认值时,您应该使用null

此属性可以设置为 null 或 Value。使用 Value 发送一个 NULL 值作为参数的值。使用 null 或不设置 Value 以使用参数的默认值。

https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlparameter.value?view=netframework-4.7.2#System_Data_SqlClient_SqlParameter_Value

由于我的参数没有默认值,因此会出现某种错误。但是,我们得到的结果似乎具有误导性:表明该参数未在数据库端收到的错误,而不是表明该参数的意外值(或者更确切地说:缺少值)的错误。

或者这实际上是预期的行为,将 Value 设置为 null 有效地排除了在执行命令时将参数传递给服务器?

2010 年 1 月 1 日更新

文档已经更新:

此属性可以设置为nullDBNull.Value。使用 DBNull.Value 发送一个 NULL 值作为参数值。使用null 或不设置Value 以使用参数的默认值。

也许不是很清楚,但至少是明确的。

这里的关键是,如果 SqlParamer 对象的 Value 属性具有 null,则为存储过程定义的参数的默认值将发挥作用,我只能假设这是“在场景”通过在查询执行中省略它。

我想这里要学习的教训是始终使用可选参数的默认值定义存储过程。

-S

【问题讨论】:

  • 正如@RomaRuzich 指出的那样,您的存储过程有一个没有默认值的参数。在存储过程中设置@TheValue varchar(50) = NULL,让它在数据库端以默认值运行。
  • 使用 DbNull.Value 而不是传递 null
  • @shahkalpesh 这不是一个解决方案。这掩盖了问题而不是解决它
  • @PanagiotisKanavos:我想 OP 正在寻找将空值传递给没有默认参数的 proc。传递 DBNull.Value 将实现这一点。但是,如果您通过null (c#),它将不会被视为DBNull.Value。您认为 OP 正在寻找什么以及您如何做到这一点?

标签: .net sql-server default-value sqlparameter


【解决方案1】:

不要如果您想将 NULL 传递给存储过程,请将值设置为 null

文档几乎是正确的。在这句话中:

使用Value发送一个NULL值作为参数值。

链接指向DbNull.Value。这是一个文档错误

传递null 而不是DbNull.Value 意味着您要使用存储过程的默认参数。文档的那部分是正确的:

使用 null 或不设置 Value 以使用参数的默认值。

更新

我刚刚为此添加了a Github issue

【讨论】:

    【解决方案2】:

    SqlParameter.Value Property

    此属性可以设置为 null 或 DBNull.Value。使用 DBNull.Value 发送一个 NULL 值作为参数的值。 使用 null 或不设置 Value 以使用参数的默认值

    所以对于value = null,您必须设置参数的默认值。

    CREATE PROCEDURE TheStoredProcedure
        @TheValue varchar(50) = NULL
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-01
      • 2021-10-17
      • 1970-01-01
      相关资源
      最近更新 更多