Exception when AddWithValue parameter is NULL

C#.Netado.net

C# Problem Overview


I have following code for specifying parameters for SQL query. I am getting following exception when I use Code 1; but works fine when I use Code 2. In Code 2 we have a check for null and hence a if..else block.

Exception:

> The parameterized query '(@application_ex_id nvarchar(4000))SELECT E.application_ex_id A' expects the parameter '@application_ex_id', which was not supplied.

Code 1:

command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);

Code 2:

if (logSearch.LogID != null)
{
         command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
}
else
{
        command.Parameters.AddWithValue("@application_ex_id", DBNull.Value );
}

QUESTION

  1. Can you please explain why it is unable to take NULL from logSearch.LogID value in Code 1 (but able to accept DBNull)?

  2. Is there a better code to handle this?

Reference:

  1. https://stackoverflow.com/questions/4555935/how-to-assign-null-to-a-sqlparameter
  2. https://stackoverflow.com/questions/13306275/datatype-returned-varies-based-on-data-in-table
  3. https://stackoverflow.com/questions/13265704/conversion-error-from-database-smallint-into-c-sharp-nullable-int?lq=1
  4. https://stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/9632050#9632050

CODE

    public Collection<Log> GetLogs(LogSearch logSearch)
    {
        Collection<Log> logs = new Collection<Log>();

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();

            string commandText = @"SELECT  *
                FROM Application_Ex E 
                WHERE  (E.application_ex_id = @application_ex_id OR @application_ex_id IS NULL)";
                
            using (SqlCommand command = new SqlCommand(commandText, connection))
            {
                command.CommandType = System.Data.CommandType.Text;

                //Parameter value setting
                //command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
                if (logSearch.LogID != null)
                {
                    command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
                }
                else
                {
                    command.Parameters.AddWithValue("@application_ex_id", DBNull.Value );
                }

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        Collection<Object> entityList = new Collection<Object>();
                        entityList.Add(new Log());

                        ArrayList records = EntityDataMappingHelper.SelectRecords(entityList, reader);

                        for (int i = 0; i < records.Count; i++)
                        {
                            Log log = new Log();
                            Dictionary<string, object> currentRecord = (Dictionary<string, object>)records[i];
                            EntityDataMappingHelper.FillEntityFromRecord(log, currentRecord);
                            logs.Add(log);
                        }
                    }

                    //reader.Close();
                }
            }
        }

        return logs;
    }

C# Solutions


Solution 1 - C#

Annoying, isn't it.

You can use:

command.Parameters.AddWithValue("@application_ex_id",
       ((object)logSearch.LogID) ?? DBNull.Value);

Or alternatively, use a tool like "dapper", which will do all that messing for you.

For example:

var data = conn.Query<SomeType>(commandText,
      new { application_ex_id = logSearch.LogID }).ToList();

I'm tempted to add a method to dapper to get the IDataReader... not really sure yet whether it is a good idea.

Solution 2 - C#

I find it easier to just write an extension method for the SqlParameterCollection that handles null values:

public static SqlParameter AddWithNullableValue(
    this SqlParameterCollection collection,
    string parameterName,
    object value)
{
    if(value == null)
        return collection.AddWithValue(parameterName, DBNull.Value);
    else
        return collection.AddWithValue(parameterName, value);
}

Then you just call it like:

sqlCommand.Parameters.AddWithNullableValue(key, value);

Solution 3 - C#

Just in case you're doing this while calling a stored procedure: I think it's easier to read if you declare a default value on the parameter and add it only when necessary.

SQL:

DECLARE PROCEDURE myprocedure
    @myparameter [int] = NULL
AS BEGIN

C#:

int? myvalue = initMyValue();
if (myvalue.hasValue) cmd.Parameters.AddWithValue("myparamater", myvalue);

Solution 4 - C#

some problem, allowed with Necessarily set SQLDbType

command.Parameters.Add("@Name", SqlDbType.NVarChar);
command.Parameters.Value=DBNull.Value

where SqlDbType.NVarChar you type. Necessarily set SQL type.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLCJView Question on Stackoverflow
Solution 1 - C#Marc GravellView Answer on Stackoverflow
Solution 2 - C#AxiomaticNexusView Answer on Stackoverflow
Solution 3 - C#z00lView Answer on Stackoverflow
Solution 4 - C#user1599225View Answer on Stackoverflow