Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing array of ints to T-SQL stored proc via entity framework

I've read many posts and think I understand the concepts, but my small array of ints fails to pass from a C#/EF module to a SQL Server stored proc. Hoping other eyes can spot the problem.

I'm using EF6, 4.5 .Net Framework, SQL Server 2014

In the database I've created these types/procs:

CREATE TYPE [dbo].[IntsTTV] AS TABLE(
  [Id] [int] NOT NULL
)

Note that a table named 'Person' exists with columns 'Id' (int) and 'LastName' (nvarchar), and has data.

CREATE PROCEDURE [dbo].[GetUsers]
@UserIds dbo.IntsTTV READONLY
AS
BEGIN
  SELECT p.LastName
  FROM [dbo].[Person] p
  INNER JOIN @UserIds ids On p.Id = ids.Id;
END

// C# code

SqlMetaData[] columns = new SqlMetaData[1];
columns[0] = new SqlMetaData("Id", SqlDbType.Int);

SqlDataRecord row = new SqlDataRecord(columns);
row.SetInt32(0, 1);  // Id of '1' is valid for the Person table

SqlDataRecord[] table = new SqlDataRecord[1];
table[0] = row;

SqlParameter parameter = new SqlParameter();
parameter.SqlDbType = SqlDbType.Structured;
parameter.ParameterName = "@UserIds";
parameter.TypeName = "dbo.IntsTTV";
parameter.Direction = ParameterDirection.Input;
parameter.Value = table;

SqlParameter[] parameters = new SqlParameter[1];
parameters[0] = parameter;


var res = _db.Database.SqlQuery<string>("GetUsers", parameters).ToList();

The code does successfully call the proc, and if I hard code the proc to simply return a select of LastName's then the C# code does receive that. This tells me what is working.

If I call the proc from other T-SQL code, passing in a prepared table-valued parameter (IntsTTV) of ints, it works.

In the proc, if I select count of rows of the passed parameter table I get zero when calling from the C# code, but I get a correct count when calling from T-SQL code.

What am I missing, please?

like image 203
gerryM Avatar asked Oct 12 '17 12:10

gerryM


People also ask

How do you declare an array variable in SQL?

Define arrays as SQL variables. Use the ARRAY_AGG built-in function in a cursor declaration, to assign the rows of a single-column result table to elements of an array. Use the cursor to retrieve the array into an SQL out parameter. Use an array constructor to initialize an array.


2 Answers

This is how I call stored procedure with table valued parameter. The main difference being that I use a DataTable parameter.

I remember having issues with parameter name bindings, but I don't remeber exactly what they were. This explains the change I made in the syntax of the procedure call. I know this one should be working.

var dataTable = new DataTable();
dataTable.TableName = "dbo.IntsTTV";
dataTable.Columns.Add("Id", typeof(int));
dataTable.Rows.Add(1); // Id of '1' is valid for the Person table

SqlParameter parameter = new SqlParameter("UserIds", SqlDbType.Structured);
parameter.TypeName = dataTable.TableName;
parameter.Value = dataTable;

var res = _db.Database.SqlQuery<string>("EXEC GetUsers @UserIds", parameter).ToList();
like image 132
jbl Avatar answered Oct 19 '22 23:10

jbl


I know this has been answered by found a different way that might help someone else out there

STRING_SPLIT

declare @intArray nvarchar(1000)
set @intArray = '1,2,3,4,5'
select value from STRING_SPLIT(@intArray , ',')

This will return a new table with the numbers in your @intArray

Then you just need to use it as a normal table

select * from myMainTable where Id in (select value from STRING_SPLIT(@intArray , ','))
like image 43
Geens Avatar answered Oct 19 '22 23:10

Geens