I have a procedure that takes in a table-valued parameter, along with others:
CREATE PROCEDURE [dbo].[Update_Records]
@currentYear INT,
@country INT,
@records Record_Table_Type READONLY
AS
and am trying to call this with Dapper.TVP.
Here is the code I have so far:
var recordsParameter = new List<SqlDataRecord>();
// This metadata matches 'Record_Table_Type' in the Database
var recordsMetaData = new[]
{
new SqlMetaData("OriginalValue", SqlDbType.Decimal, 19, 4),
new SqlMetaData("NewValue", SqlDbType.Decimal, 19, 4),
new SqlMetaData("NewPercent", SqlDbType.Decimal, 7, 2),
};
foreach (var r in records)
{
var record = new SqlDataRecord(recordsMetaData);
record.SetDecimal(0, r.OriginalValue);
record.SetDecimal(1, r.NewValue);
record.SetDecimal(2, r.NewPercent);
recordsParameter.Add(record);
}
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
});
var recordsParam = new TableValueParameter("@records", "Record_Table_Type", recordsParameter);
using (var connection = ConnectionFactory.GetConnection())
{
connection.Execute("Update_Records", ???, commandType: CommandType.StoredProcedure);
}
My issue is how do I pass both sets of parameters to the procedure in the call to Dapper Execute()
?
I have tried:
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
records = new TableValueParameter("@records", "Record_Table_Type", recordsParameter);
});
connection.Execute("Update_Records", spParams, commandType: CommandType.StoredProcedure);
and
connection.Execute("Update_Records", new Object[] { spParams, recordsParam }, commandType: CommandType.StoredProcedure);
Both call the procedure, but pass an empty table parameter ( SELECT COUNT(*) FROM @records
returns 0 )
I can't seem to find any actual documentation or source for Dapper.TVP, so the whole thing is very confusing, and the 2nd parameter to .Execute()
is just a dynamic
so that again doesn't tell me what I can and can't pass to it.
Any ideas?
You can use table-valued parameters to encapsulate rows of data in a client application and send the data to the server in a single parameterized command. The incoming data rows are stored in a table variable that can then be operated on by using Transact-SQL.
Table-valued parameters are declared by using user-defined table types. You can use table-valued parameters to send multiple rows of data to a Transact-SQL statement or a routine, such as a stored procedure or function, without creating a temporary table or many parameters.
The DynamicParameters type provides an Add method, enabling you to pass explicit parameters, specifying the datatype, direction and size: var parameters = new DynamicParameters(); var customerId = "ALFKI"; parameters. Add("@CustomerId", customerId, DbType.
I am on mobile and may be misunderstanding the question, but this should be just:
DataTable records = ...
connection.Execute("Update_Records",
new {
currentYear = filter.currentYear,
country = filter.country,
records
},
commandType: CommandType.StoredProcedure
);
Based on an answer from Mark Gravell here: Does Dapper support SQL 2008 Table-Valued Parameters?
I changed my code to no longer use Dapper.TVP and instead just use a DataTable
so the code is now:
var recordsTable = new DataTable();
recordsTable.Columns.Add("NewValue", typeof(Decimal));
foreach (var netRevenue in records)
{
var row = recordsTable.NewRow();
row[0] = netRevenue.NewValue;
recordsTable.Rows.Add(row);
}
recordsTable.EndLoadData();
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
records = recordsTable.AsTableValuedParameter("Record_Table_Type")
});
using (var connection = ConnectionFactory.GetConnection())
{
connection.Execute("Update_Records", spParams, commandType: CommandType.StoredProcedure);
}
And this works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With