Reputation: 7307
I had a need to pass an integer array to a stored procedure from .NET and so I googled the topic and eventually ran across Arrays and Lists in SQL Server 2008, written by Erland Sommarskog and supposedly considered the standard manner in which one goes about this process.
I've tried two different manners to pass a user-defined table type to a stored procedure, but I'm getting exceptions with each one. Both of these manners are similar to what Erland Sommarskog uses in the link above.
Manner #1 - Use DataTable as SqlParameter
DataTable dt = new DataTable();
dt.Columns.Add("n", typeof(int));
// Just adding 3 test rows to the DataTable
DataRow dr = dt.NewRow();
dr["n"] = 1;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["n"] = 2;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["n"] = 3;
dt.Rows.Add(dr);
// Creation of the SqlParameter
SqlParameter p = new SqlParameter();
p.ParameterName = "@ids";
p.Direction = ParameterDirection.Input;
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "lstInt_TblType";
p.Value = dt;
// Blows up here
DataSet ds = DAWrapper.GetDataSet(
Common.GetDB(),
"usp_Test",
new SqlParameter[] { p });
The exception that I get states: The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 1 ("@ids"): Data type 0x62 (sql_variant) has an invalid type for type-specific metadata.
Manner 2 - Use List as SqlParameter
List<SqlDataRecord> lstSDR = new List<SqlDataRecord>();
SqlMetaData[] tvp_definition = { new SqlMetaData("n", SqlDbType.Int) };
// Just adding 3 test rows
SqlDataRecord rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 50);
lstSDR.Add(rec);
rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 51);
lstSDR.Add(rec);
rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 52);
lstSDR.Add(rec);
// Creation of the SqlParameter
SqlParameter p = new SqlParameter();
p.ParameterName = "@ids";
p.Direction = ParameterDirection.Input;
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "lstInt_TblType";
p.Value = lstSDR;
// Blows up here
DataSet ds = DAWrapper.GetDataSet(
Common.GetDB(),
"usp_Test",
new SqlParameter[] { p });
And the exception that I get for this ones states: No mapping exists from object type System.Collections.Generic.List`1[[Microsoft.SqlServer.Server.SqlDataRecord, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] to a known managed provider native type.
Other Info lstInt_TblType is the User-Defined Table Type in my SQL Server 2008. It does exist (I triple-checked this!). It has one column called "n", of type int, primary key and doesn't allow nulls. I copied exactly how Erland set his up.
I also verified that the stored procedure usp_Test works from SQL Server Manager Studio, so I'm fairly certain that the exceptions are not issuing from that direction. This is the t-sql that I used to verify that the stored procedure works:
DECLARE @ids lstInt_TblType
INSERT @ids(n) VALUES(1),(2),(3)
EXEC usp_Test ids
Any suggestions on where to go with this would be greatly appreciated. Thanks!
*EDIT: * The stored procedure usp_Test:
ALTER PROCEDURE [dbo].[usp_Test]
(
@ids lstInt_TblType READONLY
)
AS
BEGIN
SET NOCOUNT ON;
select *
from dbo.dat_MetaData
where MetaDataTypeID in (select n from @ids)
END
GO
Upvotes: 4
Views: 7133
Reputation: 1
You can also find good examples of how to pass table-valued parameter data to a stored procedure in Microsoft's own Table-Valued Parameters reference.
Upvotes: 0
Reputation: 7307
Found a different way to go about doing it. This way uses the System.Data.SqlClient libraries to create a connection to the database, specify the stored procedure name, and then pass a parameter in as a DataTable that serves as the SQL Server user-defined table type.
using (SqlConnection conn = new SqlConnection(connStr)) {
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.usp_Test";
cmd.Parameters.AddWithValue("@ids", dt);
conn.Open();
using (SqlDataReader sqlReader = cmd.ExecuteReader()) {
DataTable retTbl = new DataTable();
retTbl.Load(sqlReader);
}
}
Upvotes: 2