101

I'm getting this exception:

The parameterized query '(@Name nvarchar(8),@type nvarchar(8),@units nvarchar(4000),@rang' expects the parameter '@units', which was not supplied.

My code for inserting is:

public int insertType(string name, string type, string units = "N\\A", string range = "N\\A", string scale = "N\\A", string description = "N\\A", Guid guid = new Guid())
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        SqlCommand command = new SqlCommand();
        command.CommandText = "INSERT INTO Type(name, type, units, range, scale, description, guid) OUTPUT INSERTED.ID VALUES (@Name, @type, @units, @range, @scale, @description, @guid) ";
        command.Connection = connection;
        command.Parameters.AddWithValue("@Name", name);
        command.Parameters.AddWithValue("@type", type);
        command.Parameters.AddWithValue("@units", units);
        command.Parameters.AddWithValue("@range", range);
        command.Parameters.AddWithValue("@scale", scale);
        command.Parameters.AddWithValue("@description", description);
        command.Parameters.AddWithValue("@guid", guid);
        return (int)command.ExecuteScalar();
    }
}

The exception was a surprise because I'm using the AddWithValue function and making sure I added a default parameters for the function.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Yogevnn
  • 1,430
  • 2
  • 18
  • 37
  • @AndrewMorton: Why does the error message complain about `@units` rather than `@Name`, which appears first? – O. R. Mapper May 03 '14 at 18:41
  • @O.R.Mapper I suppose it doesn't have to look for them in the order they are supplied. – Andrew Morton May 03 '14 at 18:43
  • @Yogevnn Ahh, `command.Parameters.AddWithValue("Name", @name)` should be `command.Parameters.AddWithValue("@Name", name)` etc. – Andrew Morton May 03 '14 at 19:15
  • @Yogevnn can you show here script for creation [Type] table? – Denis May 03 '14 at 19:26
  • @Yogevnn I suspect `AddWithValue` is guessing something wrong. Try using the [SqlParameter Constructor (String, SqlDbType, Int32)](http://msdn.microsoft.com/en-us/library/hex23w80%28v=vs.110%29.aspx). – Andrew Morton May 03 '14 at 19:33
  • ghost - I created it from the editor, what would you like to know about the table? @GrantWinney I think it may be empty, while i'm checking it, let's assume it is, how can i fix that? – Yogevnn May 03 '14 at 19:33
  • @GrantWinney yes they are all empty (all the one's with default) – Yogevnn May 03 '14 at 19:37
  • 1
    possible duplicate of [The parameterized query expects the parameter which was not supplied](http://stackoverflow.com/questions/3865982/the-parameterized-query-expects-the-parameter-which-was-not-supplied) – Gopi Jun 01 '15 at 17:15

6 Answers6

131

Try this code:

SqlParameter unitsParam = command.Parameters.AddWithValue("@units", units);
if (units == null)
{
    unitsParam.Value = DBNull.Value;
}

And you must check all other parameters for null value. If it null you must pass DBNull.Value value.

Denis
  • 5,894
  • 3
  • 17
  • 23
  • 1
    I dont think it could be null because OP has the parameter like this `string units = "N\\A"` – meda May 03 '14 at 19:41
  • 3
    It could, because you can call method like this `insertType(null, null, null, null, null, null);` – Denis May 03 '14 at 19:44
  • @GrantWinney Apparently that is not how it works. The parameter has to be omitted from the calling code rather than set to `null`. [Named and Optional Arguments](http://msdn.microsoft.com/en-us/library/dd264739.aspx) – Andrew Morton May 03 '14 at 20:05
  • @GrantWinney Defaults don't work like that. They only apply when you don't pass *anything* (if you omit the argument altogether). If you pass anything at all, even `null`, then what you pass is what the callee sees. –  May 03 '14 at 20:05
  • 2
    A shorter way to write this is `command.Parameters.AddWithValue("@units", (object)units ?? DBNull.Value)`. – Der Kommissar Apr 10 '16 at 20:07
51

Here's a way using the null-coalescing operator:

cmd.Parameters.AddWithValue("@units", units ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@range", range ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@scale", scale ?? (object)DBNull.Value);
cmd.Parameters.AddWithValue("@description", description ?? (object)DBNull.Value);

Or for more strict type checking:

cmd.Parameters.Add("@units", SqlDbType.Int).Value = units ?? (object)DBNull.Value;
cmd.Parameters.Add("@range", SqlDbType.Int).Value = range ?? (object)DBNull.Value;
cmd.Parameters.Add("@scale", SqlDbType.Int).Value = scale ?? (object)DBNull.Value;
cmd.Parameters.Add("@description", SqlDbType.VarChar).Value = description ?? (object)DBNull.Value;

The operator also be chained:

int?[] a = { null, null, 1 };
Console.WriteLine(a[0] ?? a[1] ?? a[2]);
Will
  • 1,048
  • 9
  • 10
5

This extension class was useful to me a couple of times so far, for those issues:

public static class DbValueExtensions
{
    // Used to convert values coming from the db
    public static T As<T>(this object source)
    {
        return source == null || source == DBNull.Value
            ? default(T)
            : (T)source;
    }

    // Used to convert values going to the db
    public static object AsDbValue(this object source)
    {
        return source ?? DBNull.Value;
    }
}

You would normally use it in two scenarios. First, when creating parameters for your query:

var parameters = new Dictionary<string, object>
{
    { "@username", username.AsDbValue() },
    { "@password", password.AsDbValue() },
    { "@birthDate", birthDate.AsDbValue() },
};

or when parsing the SqlReader values:

while (reader.Read())
{
    yield return new UserInfo(
        reader["username"].As<string>(),
        reader["birthDate"].As<DateTime>(),
        reader["graduationDate"].As<DateTime?>(),
        reader["nickname"].As<string>()
    );
}
Mladen B.
  • 2,784
  • 2
  • 23
  • 34
3
command.Parameters.AddWithValue("@Name", (name == null ? "" : name));
johnnyRose
  • 7,310
  • 17
  • 40
  • 61
Saad
  • 79
  • 2
1

This is a method to be reused with multiple parameters:

public void NullorEmptyParameter(QC.SqlCommand command, string at, string value)
{
    if (String.IsNullOrEmpty(value))
    {
        command.Parameters.AddWithValue(at, DBNull.Value);
    }
    else
        command.Parameters.AddWithValue(at, value);
}

And then you can reuse it for as many commands and params:

NullorEmptyParameter(command, "@Idea_ID", Idea_ID);
NullorEmptyParameter(command, "@Opportunities_or_Idea", Opportunities_or_Idea);
johnnyRose
  • 7,310
  • 17
  • 40
  • 61
locnguyen
  • 66
  • 6
-1

Migrating OP's solution from the question to an answer:

The problem was that the some parameters were empty Strings (that override the default)

This is the working code:

public int insertType(string name, string type, string units = "N\\A", string range = "N\\A", string scale = "N\\A", string description = "N\\A", Guid guid = new Guid())
   {
       using (SqlConnection connection = new SqlConnection(connectionString))
       {
           connection.Open();
           SqlCommand command = new SqlCommand();
           command.CommandText = "INSERT INTO Type(name, type, units, range, scale, description, guid) OUTPUT INSERTED.ID VALUES (@Name, @type, @units, @range, @scale, @description, @guid) ";
           command.Connection = connection;
           command.Parameters.AddWithValue("@Name", name);
           command.Parameters.AddWithValue("@type", type);

           if (String.IsNullOrEmpty(units))
           {
               command.Parameters.AddWithValue("@units", DBNull.Value); 
           }
           else
               command.Parameters.AddWithValue("@units", units);
           if (String.IsNullOrEmpty(range))
           {
               command.Parameters.AddWithValue("@range", DBNull.Value);
           }
           else
               command.Parameters.AddWithValue("@range", range);
           if (String.IsNullOrEmpty(scale))
           {
               command.Parameters.AddWithValue("@scale", DBNull.Value);
           }
           else
               command.Parameters.AddWithValue("@scale", scale);
           if (String.IsNullOrEmpty(description))
           {
               command.Parameters.AddWithValue("@description", DBNull.Value);
           }
           else
               command.Parameters.AddWithValue("@description", description);
                    
           command.Parameters.AddWithValue("@guid", guid);

           return (int)command.ExecuteScalar();
       }
   }
TylerH
  • 20,799
  • 66
  • 75
  • 101