SqlParameter "disappears" 什么时候赋值为null?

SqlParameter "disappears" when assigned a value of null?

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

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

我有一个数据库 table,其中有一列接受 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

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

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);
    }
}

前两个方法调用 运行 没问题:第一个将字符串添加到 table,第二个添加一个 NULL,但调用 ExecuteStoredProcedure() 时使用 null 导致以下错误:

System.Data.SqlClient.SqlException (0x80131904): Procedure or function 'TheStoredProcedure' expects parameter '@TheValue', which was not supplied.

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

This property can be set to null or Value. Use Value to send a NULL value as the value of the parameter. Use null or do not set Value to use the default value for the parameter.

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

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

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

2010 年 1 月更新

文档已更新:

This property can be set to null or DBNull.Value. Use DBNull.Value to send a NULL value as the value of the parameter. Use null or do not set Value to use the default value for the parameter.

可能不crystal清楚,但至少是明确的。

这里的关键是,如果 SqlParamer 对象的值 属性 具有 null,那么为存储过程定义的参数的默认值就会起作用,并且我只能假设这是通过从查询执行中省略它来实现的 "behind the scenes"。

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

-S

SqlParameter.Value Property

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

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

CREATE PROCEDURE TheStoredProcedure
    @TheValue varchar(50) = NULL

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

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

Use Value to send a NULL value as the value of the parameter.

link指向DbNull.Value。这是文档错误

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

Use null or do not set Value to use the default value for the parameter.

更新

我刚刚为此添加了 a Github issue