Binding empty list or null value to table valued parameter on a stored procedure (.NET)

.NetSql Server-2008Stored ProceduresTable Valued-Parameters

.Net Problem Overview


I have created a stored procedure that takes a table valued parameter that is a table with a single column of type int. The idea is to simply pass a list of ids into the store procedure and allow the stored procedure to work with the data. However, in the case where there is no data to pass in, I am encountering problems (things work correctly when I have data). I am converting a List<int> to an IEnumerable<SqlDataRecord>, and binding that to the table valued parameter for the stored procedure. I have tried to bind an empty List<SqlDataRecord>, which resulted in the error:

> System.ArgumentException: There are no records in the SqlDataRecord enumeration. To send a table-valued parameter with no rows, use a null reference for the value instead.

I then tried to bind a null value (which I thought was what the above message was getting at), but that only resulted in a different error message

> System.NotSupportedException: DBNull value for parameter '@MainItemIdList' is not supported. Table-valued parameters cannot be DBNull.

It does not appear that you can declare the table valued parameter as nullable in the stored procedure declaration. What is the correct method for binding an empty list to at table valued parameter?

.Net Solutions


Solution 1 - .Net

The trick is: don’t pass in the parameter at all. The default value for a table-valued parameter is an empty table.

It is a shame that the exception message is so unhelpful.

Solution 2 - .Net

I was a bit confused by what the 'not passing the parameter' statement means. What ends up working for Entity Framework ExecuteSqlCommandAsync() is this:

  new SqlParameter("yourParameterName", SqlDbType.Structured)
  {
      Direction = ParameterDirection.Input,
      TypeName = "yourUdtType",
      Value = null
  };

This will pass the parameter as 'default'.

Solution 3 - .Net

Not passing a value does work but not in the case where I had multiple table value parameters to pass into the procedure. How I solved it was to specify a value of DEFAULT in my query string. For example,

string sqlQuery = "[dbo].[GetOrderData] @QueueId";

if (OrderIdList.Any())
{
    sqlQuery = sqlQuery + ", @OrderIdList";
}
else
{
    sqlQuery = sqlQuery + ", DEFAULT";
}

if (RegionIdList.Any())
{
    sqlQuery = sqlQuery + ", @RegionIdList";
}
else
{
    sqlQuery = sqlQuery + ", DEFAULT";
}

Kudos to http://www.sommarskog.se/arrays-in-sql-2008.html#Invoking where I found the solution for this.

Solution 4 - .Net

I get the error when passing an empty IEnumerable<int> but it works fine when I pass an empty List<int> instead.

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
QuestionBrian JonesView Question on Stackoverflow
Solution 1 - .NetDaniel CassidyView Answer on Stackoverflow
Solution 2 - .NetNoppeyView Answer on Stackoverflow
Solution 3 - .NetAnthonyView Answer on Stackoverflow
Solution 4 - .NetjauselView Answer on Stackoverflow