The point about temporary tables is that they're limited to the scope of the connection. Dapper will automatically open and close a connection if it's not already opened. That means that any temp table will be lost directly after creating it, if the connection passed to Dapper has not been opened.
This will not work:
private async Task<IEnumerable<int>> SelectWidgetsError()
{
using (var conn = new SqlConnection(connectionString))
{
await conn.ExecuteAsync(@"CREATE TABLE #tmpWidget(widgetId int);");
// this will throw an error because the #tmpWidget table no longer exists
await conn.ExecuteAsync(@"insert into #tmpWidget(WidgetId) VALUES (1);");
return await conn.QueryAsync<int>(@"SELECT * FROM #tmpWidget;");
}
}
On the other hand, these two versions will work:
private async Task<IEnumerable<int>> SelectWidgets()
{
using (var conn = new SqlConnection(connectionString))
{
// Here, everything is done in one statement, therefore the temp table
// always stays within the scope of the connection
return await conn.QueryAsync<int>(
@"CREATE TABLE #tmpWidget(widgetId int);
insert into #tmpWidget(WidgetId) VALUES (1);
SELECT * FROM #tmpWidget;");
}
}
private async Task<IEnumerable<int>> SelectWidgetsII()
{
using (var conn = new SqlConnection(connectionString))
{
// Here, everything is done in separate statements. To not loose the
// connection scope, we have to explicitly open it
await conn.OpenAsync();
await conn.ExecuteAsync(@"CREATE TABLE #tmpWidget(widgetId int);");
await conn.ExecuteAsync(@"insert into #tmpWidget(WidgetId) VALUES (1);");
return await conn.QueryAsync<int>(@"SELECT * FROM #tmpWidget;");
}
}