Dapper: inserting rows into table variables
Asked Answered
D

3

5

i have lately been using dapper and all in all had no problems with it except when using table variables.

For demonstration, I use a modified example from this thread.

This code works without problems:

int tally = connection.Execute(
    "create table #t(Name nvarchar(max), Age int)\n" +
    "insert #t (Name,Age) values(@Name, @Age)", new[]
    {
        new {Age = 1, Name = "sam"},
        new {Age = 2, Name = "bob"}
    });

But this doesn't:

int tally = connection.Execute(
    "create table @t(Name nvarchar(max), Age int)\n" +
    "insert @t (Name,Age) values(@Name, @Age)", new[]
    {
        new {Age = 1, Name = "sam"},
        new {Age = 2, Name = "bob"}
    });

The only change is the use of table variables instead temporary tables (@ instead #). Dapper (or anything other in the chain?) seems to somehow mix this up with parameters and returns "Must declare the table variable @t".

Is there anything wrong in my usage or is this a bug/missing feature in dapper?

Best regards, Kc


UPDATE:

Just to clarify: @t is not a parameter to be set by dapper. @t is declared as a local table that's only existent for the currently running query. In my opinion, dapper should not distinguish between any type of table, be it a "normal" one, local/global temporary table or table variable.

A little bit more background information:

What I really want to do is:

  • Insert a list of Ids into an indexed table variable (or maybe temporary table if table variables don't work)
  • JOIN this table against one of my persistent tables and return the result.

My intention is to defeat a performance issue when SELECTing from my tables with an WHERE IN (...) clause

Daubigny answered 11/1, 2014 at 9:30 Comment(2)
did you find a solution that works?Decolorize
@EakanGopalakrishnan: No, sorry. This question is almost 8 years old. I have not been using Dapper lately.Daubigny
S
6

If you're using SQL Server, then the syntax is incorrect. In SQL Server, table variables are not created the same way as regular tables. It should be like this:

DECLARE @t TABLE (
   -- table definition
);
Spatial answered 6/10, 2014 at 17:41 Comment(0)
A
2

You said:

My intention is to defeat a performance issue when SELECTing from my tables with an WHERE IN (...) clause

I'm also worried about performance. I have a huge table and I need to SELECT a small subset of it each time I query.

What seems to work for me is to create a DataTable in C# and pass it to Dapper's AsTableValuedParameter method. Then I would:

JOIN this table against one of my persistent tables and return the result.

e.g.,

First in my db I created a UDTT:

 CREATE TYPE [dbo].[IDs] AS TABLE(
    [ID] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)

Then in my code create a DataTable:

        var dt = new DataTable();
        dt.Columns.Add(new DataColumn("Id", typeof(long)));

//i'm adding from a list passed as parameter; your example is via collection initializer
        foreach (var id in Ids)
        {
            dt.Rows.Add(id);
        }

Then write a query that joins the large table to my subset:

        using (IDbConnection sqlConnection = new SqlConnection(connectionString))
        {

            const string query = @"

SELECT *
FROM [dbo].[Candidate] c
JOIN @tvp t ON c.CandidateID = t.ID

";
            var candList = sqlConnection.Query<Candidate>(query, new { tvp = dt.AsTableValuedParameter("[dbo].[IDs]") }).ToList();

            return candList;
        }
Ardolino answered 24/5, 2017 at 19:7 Comment(0)
K
1

You're using it wrong. Dapper and all other micro-Orms don't care about table variables as defined by the whatever sql flavour, they care only about sql parameters.

You should do this (assuming the table name doesn't come from user input - and why should it?!)

var tableName='my_table' ;
int tally = connection.Execute(
string.format("create table {0}(Name nvarchar(max), Age int)\n" +
"insert {0} (Name,Age) values(@Name, @Age)",tableName), new[]
{
    new {Age = 1, Name = "sam"},
    new {Age = 2, Name = "bob"}
});
Kollwitz answered 11/1, 2014 at 9:57 Comment(3)
Ok, maybe a little bit more background will help. What I really want to do is: 1. Insert a list of Ids into an indexed table variable (or maybe temporary table if table variables don't work), 2. JOIN this table against one of my persistent tables and return the result. My intention is to defeat a performance issue when SELECTing from my tables with an WHERE IN (...) clauseDaubigny
I think your problem is sql related not dapper related. Dapper is just a data mapper, taking care of the boring create connection, command, assign parameter to command then map the data reader to an object.Kollwitz
this might be. but i tested my query successfully in SQL Management Studio and thought it should be straight forward to use it in dapper. Since inserting multiple objects into a table is supported as well, I thought this should be possible.Daubigny

© 2022 - 2024 — McMap. All rights reserved.