13

I need to use Table Valued Parameter with string query

I have the following code

string query = "SELECT * FROM Tabla1 T1 INNER JOIN @listItems T2 ON T2.Id = T1.Id";
var results = sqlConnection.Query(query , new TableValuedParameter<string>("@listItems", "string_list_Type", valuesList));

the variable valueList is a List

The execution give me a error: "Could not find stored procedure"

Is posible usa table valued parameters without use procedure ?

thanks regards

Leandro Tuttini
  • 803
  • 3
  • 8
  • 16
  • What you have posted does not even compile. "The non-generic type 'Dapper.TableValuedParameter' cannot be used with type arguments" – Darek Aug 21 '15 at 17:13
  • Also, it seems that TableValuedParameter is an ``internal`` class so you can't create a new instance of it directly. – Darek Aug 21 '15 at 17:24
  • @Darek they probably used one of the generic TableValuedParameter implementations. I have something similar and run into the exact same error. – Tom Lint Dec 14 '21 at 14:21
  • Does the answer below help? @TomLint – Darek Feb 14 '22 at 18:44

2 Answers2

28

Without seeing full code sample it is hard to tell what the problem could be. Consider this, which executes perfectly fine:

First, TVP definition

CREATE TYPE [dbo].[TVPSTRING] AS TABLE(
    [VALUE] NVARCHAR(MAX) NULL
)

Then sample Dapper code:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Dapper;

namespace CPTVP
{
    class Program
    {
        static void Main(string[] args)
        {
            var dt = new DataTable();
            dt.Columns.Add("StringsStringsEverywhere", typeof(string));
            foreach (int i in Enumerable.Range(0,10))
            {
                dt.Rows.Add(string.Format("{0:0000}", i));
            }

            using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Scratch;Integrated Security=true;"))
            {
                Console.WriteLine(String.Join("\n", conn.Query<string>("SELECT * FROM @tvpstr", new {tvpstr=dt.AsTableValuedParameter("dbo.TVPSTRING")})));
            }
        }
    }
}
Darek
  • 4,687
  • 31
  • 47
0

Assuming the OP used the same generic TableValuedParameter class I did, the solution lies in its implementation of the SqlMapper.IDynamicParameters AddParameters method, and the fact that it explicitly sets the CommandType of the IDbCommand to CommandType.StoredProcedure as shown below:

public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
    var sqlCommand = (SqlCommand)command;
    sqlCommand.CommandType = CommandType.StoredProcedure;
    var list = _values.Select(s =>
    {
        var sqlDataRecord = new SqlDataRecord(_tvpDefinition);
        _actionMapping(sqlDataRecord, s);
        return sqlDataRecord;
    }).ToList();

    if (list.Count == 0)
    {
        return;
    }

    var sqlParameter = sqlCommand.Parameters.Add(_name, SqlDbType.Structured);
    sqlParameter.Direction = ParameterDirection.Input;
    sqlParameter.TypeName = _typeName;
    sqlParameter.Value = list;
}

By removing the line that explicitly sets the CommandType, the TableValuedParameter class now works for normal queries, too.

Tom Lint
  • 483
  • 5
  • 13