Does anyone know if is possible to pass table-valued parameter data to a stored procedure with Dapper?
- 
                    1Alternatively you can use bulkinsert to a temp table http://stackoverflow.com/a/9947259/37055 – Chris Marisic Feb 26 '15 at 17:10
 
4 Answers
There is now (n Dapper 1.26 and higher) direct support for table-valued parameters baked into dapper. In the case of stored procedures, since the data type is built into the sproc API, all you need to do is supply a DataTable:
var data = connection.Query<SomeType>(..., new {
    id=123, name="abc", values = someTable
}, ...);
For direct command-text you have two other options:
use a helper method to tell it the custom data type:
var data = connection.Query<SomeType>(..., new { id=123, name="abc", values = someTable.AsTableValuedParameter("mytype") }, ...);tell the data-table itself what custom data type to use:
someTable.SetTypeName("mytype"); var data = connection.Query<SomeType>(..., new { id=123, name="abc", values = someTable }, ...);
Any of these should work fine.
- 1,026,079
 - 266
 - 2,566
 - 2,900
 
- 
                    A case where I am not able to add a TVP using Dapper, if I need a Non Input parameter addition along with, using Dynamic Parameters, I am not able to add TVP, please check my question @ http://stackoverflow.com/questions/33087629/dapper-dynamic-parameters-with-table-valued-parameters – Mrinal Kamboj Oct 15 '15 at 07:28
 - 
                    9
 - 
                    With `ExecuteReader`, I get, "The member events of type System.Data.DataTable cannot be used as a parameter value". – Ian Warburton Mar 07 '18 at 19:25
 
Yes, we support them but you will need to code your own helpers.
For example:
class IntDynamicParam : Dapper.SqlMapper.IDynamicParameters
{
    IEnumerable<int> numbers;
    public IntDynamicParam(IEnumerable<int> numbers)
    {
        this.numbers = numbers;
    }
    public void AddParameters(IDbCommand command)
    {
        var sqlCommand = (SqlCommand)command;
        sqlCommand.CommandType = CommandType.StoredProcedure;
        List<Microsoft.SqlServer.Server.SqlDataRecord> number_list = new List<Microsoft.SqlServer.Server.SqlDataRecord>();
        // Create an SqlMetaData object that describes our table type.
        Microsoft.SqlServer.Server.SqlMetaData[] tvp_definition = { new Microsoft.SqlServer.Server.SqlMetaData("n", SqlDbType.Int) };
        foreach (int n in numbers)
        {
            // Create a new record, using the metadata array above.
            Microsoft.SqlServer.Server.SqlDataRecord rec = new Microsoft.SqlServer.Server.SqlDataRecord(tvp_definition);
            rec.SetInt32(0, n);    // Set the value.
            number_list.Add(rec);      // Add it to the list.
        }
        // Add the table parameter.
        var p = sqlCommand.Parameters.Add("@ints", SqlDbType.Structured);
        p.Direction = ParameterDirection.Input;
        p.TypeName = "int_list_type";
        p.Value = number_list;
    }
}
// SQL Server specific test to demonstrate TVP 
public void TestTVP()
{
    try
    {
        connection.Execute("CREATE TYPE int_list_type AS TABLE (n int NOT NULL PRIMARY KEY)");
        connection.Execute("CREATE PROC get_ints @ints int_list_type READONLY AS select * from @ints");
        var nums = connection.Query<int>("get_ints", new IntDynamicParam(new int[] { 1, 2, 3 })).ToList();
        nums[0].IsEqualTo(1);
        nums[1].IsEqualTo(2);
        nums[2].IsEqualTo(3);
        nums.Count.IsEqualTo(3);
        connection.Execute("DROP PROC get_ints");
        connection.Execute("DROP TYPE int_list_type");
    }
}
Make sure you properly test performance for table valued params. When I tested this for passing int lists it was significantly slower than passing in multiple params.
I am totally not against having some SQL Server specific helpers for dapper in the contrib project, however the core dapper avoids adding vendor specific tricks where possible.
- 128,308
 - 78
 - 326
 - 506
 
- 
                    1In fact using TVP is slower than "where col in @values". How can I use the List Support Feature (Dapper allow you to pass in IEnumerable
and will automatically parameterize your query) to pass a list of ints to a StoredProcedure? – Carlos Mendes Jul 06 '11 at 16:28 - 
                    This is one of those crazy edge cases where batches are faster than sps the technique dapper uses for list support is not compatible with stored procs – Sam Saffron Jul 06 '11 at 21:49
 - 
                    Can you update this? I can't quite figure out if it's OK to be ignoring the identity parameter in newer versions of Dapper. – Chris Pfohl Jul 07 '14 at 14:17
 - 
                    Would this code work as is or will it need IEnumerable
collection to be converted to a DataTable for be used as a TVP – Mrinal Kamboj Oct 15 '15 at 07:39 
I know this ticket is OLD, very old, but wanted to let you know that I have published Dapper.Microsoft.Sql package, which supports generic TVPs.
https://www.nuget.org/packages/Dapper.Microsoft.Sql/
Sample use:
List<char> nums = this.connection.Query<char>(
  "get_ints", 
  new TableValuedParameter<char>(
    "@ints", "int_list_Type", new[] { 'A', 'B', 'C' })).ToList();
It is based on the original classes from Dapper test project.
Enjoy!
- 4,687
 - 31
 - 47
 
- 
                    I am trying to understand how to have a TVP as a parameter along with other typical-typed parameters. How is that done? – Snowy Feb 28 '14 at 15:22
 - 
                    
 
today it isn't. We actually investigated table-valed-parameters for our cheeky "in" implementation (where col in @values), but were very unimpressed by performance. However in the context of a SPROC it makes sense.
Your best bet is to log this as an issue on the project site so we can track/prioritise it. It sounds like something will be doable, though, probably similar to the DbString or DynamicParameters options.
But today? No.
- 1,026,079
 - 266
 - 2,566
 - 2,900
 
- 
                    2correction, we sort of support it ... you just need to code it yourself :) – Sam Saffron Jun 06 '11 at 00:33
 -