分配空值时,SqlParameter“消失”吗?

时间:2018-12-07 07:23:51

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

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

向SqlParameter的Value属性分配null似乎导致查询中省略该参数,而不是传递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,但是用ExecuteStoredProcedure()调用null会导致以下错误:

  

System.Data.SqlClient.SqlException(0x80131904):过程或函数'TheStoredProcedure'期望未提供参数'@TheValue'。

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

  

此属性可以设置为null或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会有效地避免在执行命令时将参数传递给服务器?

-S

2 个答案:

答案 0 :(得分:1)

SqlParameter.Value Property

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

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

CREATE PROCEDURE TheStoredProcedure
    @TheValue varchar(50) = NULL

答案 1 :(得分:1)

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

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

  

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

链接指向 DbNull.Value 。那是文档错误

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

  

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

更新

我为此添加了a Github issue