2

I stumbled across the following issue recently:

Assigning a null to the Value property of an SqlParameter appears to cause the parameter to be omitted from the query rather than passing NULL. This results in a potentially misleading error message when the Stored Procedure has no default value for the parameter.

I have a database table with a column that accepts 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

The table is populated using a Stored Procedure. Notice that the parameter targeting the column does not specify a default value.

USE [TheDatabase]
GO

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

Executing the Stored Procedure with a value and with a NULLboth work fine:

USE [TheDatabase]
GO

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

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

I run the following code:

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

The first two method calls run fine: The first adds the string to the table, the second adds a NULL, but calling ExecuteStoredProcedure() with a null results in the following error:

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

From the documentation it appears that you should use null when you wish to use the default value of parameter in the Stored Procedure.

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://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlparameter.value?view=netframework-4.7.2#System_Data_SqlClient_SqlParameter_Value

Since my parameter does not have a default value, some sort of error is to be expected. However, what we get seems misleading: an error indicating that the parameter was not received on the database side, as opposed to an error indicating an unexpected value (or rather: lack of value) on that parameter.

Or is this in fact expected behavior, that setting Value to null effectively excludes the parameter from being passed to the server on execution of the command?

Update 20.01.2010

The documentation has since been updated:

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.

It is perhaps not crystal clear, but it is at least unambiguous.

Key here is that the default value of the parameter as defined for the Stored Procedure comes into play if the SqlParamer object has a null for its Value property, and I can only assume that this is achieved "behind the scenes" by omitting it from the query execution.

I guess the lesson to learn here is to always define your Stored Procedures with default values on your optional parameters.

-S

Sigurd Garshol
  • 1,376
  • 3
  • 15
  • 36
  • See answer here https://stackoverflow.com/questions/2113122/calling-stored-procedures-passing-null-values-dealing-with-boolean-values – Roma Ruzich Dec 07 '18 at 07:28
  • As @RomaRuzich pointed out, your stored proc has a parameter that doesnt have a default value. Set `@TheValue varchar(50) = NULL` in your stored procedure to let it run with default value on db side. – shahkalpesh Dec 07 '18 at 07:31
  • Use DbNull.Value instead of passing a `null` – Panagiotis Kanavos Dec 07 '18 at 07:40
  • @shahkalpesh that's not a solution. That covers up the problem instead of solving it – Panagiotis Kanavos Dec 07 '18 at 07:41
  • @PanagiotisKanavos: I suppose OP is looking to pass null value to the proc which doesnt have default parameter. Passing DBNull.Value will achieve that. However, if you pass `null` (c#) it won't be treated as `DBNull.Value`. What do you think OP is looking for & how do you get to that? – shahkalpesh Dec 07 '18 at 07:47
  • @shahkalpesh why do you proposed the OP *change the stored procedure* then ? – Panagiotis Kanavos Dec 07 '18 at 07:53
  • @PanagiotisKanavos: Because that is the way I think is the way it gets solved. Why do you think it "covers up the problem instead of solving it"? – shahkalpesh Dec 07 '18 at 08:07
  • @shahkalpesh you *don't* need to modify the stored procedure just to set the parameter to null. You use `DbNull.Value` instead. There's no "why do you think" about it. That's what the docs say as well, even if they seem to have a typo – Panagiotis Kanavos Dec 07 '18 at 08:10
  • Possible duplicate of [Assign null to a SqlParameter](https://stackoverflow.com/questions/4555935/assign-null-to-a-sqlparameter) – Panagiotis Kanavos Dec 07 '18 at 08:10
  • @shahkalpesh in fact, there are several duplicate questions about this – Panagiotis Kanavos Dec 07 '18 at 08:11
  • Possible duplicate of [Best method of assigning NULL value to SqlParameter](https://stackoverflow.com/questions/13981281/best-method-of-assigning-null-value-to-sqlparameter) – Panagiotis Kanavos Dec 07 '18 at 08:12
  • @PanagiotisKanavos: OP already has an example of passing `DBNull.Value` which takes care. I am not sure how does one pass null (c#) value other than using `DBNull.Value`? – shahkalpesh Dec 07 '18 at 12:03

2 Answers2

3

Don't set the value to null if you want to pass a NULL to the stored procedure

The docs are almost right. In the phrase :

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

The link points to DbNull.Value. That's a documentation error

Passing null instead of DbNull.Value means you want to use the stored procedure's default parameter. That part of the docs is correct :

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

Update

I just added a Github issue for this

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
1

SqlParameter.Value Property

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.

So for value = null you have to set a default value of your patameter.

CREATE PROCEDURE TheStoredProcedure
    @TheValue varchar(50) = NULL
Denis Rubashkin
  • 2,151
  • 1
  • 9
  • 14