How to pass byte[] to stored procedure using Entity Framework - sql-server

I have this function auto-generated by EF that calls my stored procedure passing it a byte[]:
public virtual ObjectResult<string> IPv6Country_Get(byte[] ipBytes)
{
var ipBytesParameter = ipBytes != null ?
new ObjectParameter("ipBytes", ipBytes) :
new ObjectParameter("ipBytes", typeof(byte[]));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("IPv6Country_Get", ipBytesParameter);
}
My stored procedure is:
CREATE Procedure [dbo].[IPv6Country_Get]
(
#ipBytes varbinary
)
AS
SELECT
[countrySHORT] AS Country
FROM
[IPv6Country]
WHERE
#ipBytes >= [ipFROM] AND
#ipBytes <= [ipTO]
RETURN 0
When the EF function is called the stored procedure gets only the first byte of the array in #ipBytes. What do I need to change so it receives the full byte[]?

Just add lenght of varbinary
CREATE Procedure [dbo].[IPv6Country_Get]
(
#ipBytes varbinary(max)
)

Related

I need to create a snowflake dummy stored procedure with output array as push

I need to snowflake how to create dummy stored procedure with out put array as push in snowflake.
Dummy stored procedure using Snowflake Scripting:
CREATE PROCEDURE dummy()
RETURNS ARRAY
LANGUAGE SQL
AS
$$
begin
return ARRAY_CONSTRUCT(1,2,3);
end;
$$;
CALL dummy();
-- [ 1, 2, 3 ]
DESC RESULT LAST_QUERY_ID();
-- name type kind
-- DUMMY ARRAY COLUMN
Since you mentioned pushing to the array, I'll add to Lukasz's answer to show a JavaScript example with pushing to the array in a loop:
create or replace procedure ARRAY_SAMPLE()
returns array
language javascript
as
$$
var arr = [];
var rs = snowflake.execute({sqlText:'select N_NAME from SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.NATION'});
while (rs.next()) {
arr.push(rs.getColumnValue('N_NAME'));
}
return arr;
$$;
call ARRAY_SAMPLE();

Issue with return value from stored procedure in Entity Framework with reverse POCO generator

My stored procedure looks like this:
CREATE TABLE #CategoryIdsList (CatId INT NOT NULL);
CREATE TABLE #FilteredAdsId (AdsId INT NOT NULL);
.
.
.
SELECT *
FROM my table
DROP TABLE #CategoryIdsList;
DROP TABLE #FilteredAdsId;
but the result set value in poco generator is int
int myprocedureName(int? count, string ids);
Yes, the return value (which is sent back using RETURN) is INT - as a matter of fact, it's always INT in SQL Server.
Your data that you selected from My Table is the result set that the stored procedure produces - which is vastly different from the "return value" .....

Receiving one out of few Result Sets in stored procedure

I have a stored procedure that works fine but it has inside it three "select"s.
The selects are not from an inner temporary table.
This is mainly the format of the procedure:
ALTER PROCEDURE [dbo].[STProce]
#param1 int,
#param2 int,
#param3 int,
#param4 int,
#param5 int
AS
select #param1 as p1, #param2 as p2, #param3 as p3
.
.
.
select #param4 as p4
.
.
.
select #param5 as p5
I'm executing the procedure from another procedure and need to catch it there.
I created a table and inserts into it the "exec" from the procedure, like that:
CREATE TABLE #stalledp
(
RowNumber INT,
fldid INT,
fldLastUpdated datetime,
fldCreationDate datetime,
fldName nvarchar(255),
fldPending nvarchar(255)
)
INSERT INTO #stalledp (RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC spDebuggerViews_GetStuckWorkflowInstances #workflowSpaceId='00000000-0000-0000-0000-000000000000',#pageNum=1,#pageSize=100000,#orderByColumn=N'fldid',#sortOrder=1,#workflowInstanceId=0,#stuckInstanceType=1,#createdDateFrom='1900-01-01 00:00:00',#createdDateTo='9999-01-01 23:59:59',#updatedDateFrom='1900-01-01 00:00:00',#updatedDateTo='9999-01-01 23:59:59'
Afterwards I receive this error:
Column name or number of supplied values does not match table definition.
The order and name of columns of the table is exactly like the procedure returns.
Is there a possibility to catch only one of the tables that the procedure returns and avoid the other? I cannot change the procedure at all.
I tried declaring a table the same fields as the first select of the procedure and I get an error says that
Thank you in advance!
If all of the result sets returned are of the same structure, then you can dump them to a temp table as you are trying to do. However, that only gets you so far because if the data in the fields cannot be used to determine which result set a particular row came from, then you just have all of the result sets with no way to filter out the ones you don't want.
The only way to interact with multiple result sets individually, regardless of them having the same or differing structures, is through app code (i.e. a client connection). And if you want to do this within the context of another query, then you need to use SQLCLR.
The C# code below shows a SQLCLR stored procedure that will execute a T-SQL stored procedure that returns 4 result sets. It skips the first 2 result sets and only returns the 3rd result set. This allows the SQLCLR stored procedure to be used in an INSERT...EXEC as desired.
The code for the T-SQL stored proc that is called by the following code is shown below the C# code block. The T-SQL test proc executes sp_who2 and only return a subset of the fields being returned by that proc, showing that you don't need to return the exact same result set that you are reading; it can be manipulated in transit.
C# SQLCLR proc:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class TheProc
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void Get3rdResultSetFromGetStuckWorkflowInstances()
{
int _ResultSetsToSkip = 2; // we want the 3rd result set
SqlConnection _Connection = null;
SqlCommand _Command = null;
SqlDataReader _Reader = null;
try
{
_Connection = new SqlConnection("Context Connection = true;");
_Command = _Connection.CreateCommand();
_Command.CommandType = CommandType.StoredProcedure;
_Command.CommandText = "tempdb.dbo.MultiResultSetTest";
// (optional) add parameters (but don't use AddWithValue!)
// The SqlDataRecord will be used to define the result set structure
// and act as a container for each row to be returned
SqlDataRecord _ResultSet = new SqlDataRecord(
new SqlMetaData[]
{
new SqlMetaData("SPID", SqlDbType.Char, 5),
new SqlMetaData("Status", SqlDbType.NVarChar, 30),
new SqlMetaData("Login", SqlDbType.NVarChar, 128),
new SqlMetaData("HostName", SqlDbType.NVarChar, 128),
new SqlMetaData("BlkBy", SqlDbType.VarChar, 5),
new SqlMetaData("DBName", SqlDbType.NVarChar, 128)
});
SqlContext.Pipe.SendResultsStart(_ResultSet); // initialize result set
_Connection.Open();
_Reader = _Command.ExecuteReader();
// Skip a predefined number of result sets
for (int _Index = 0;
_Index < _ResultSetsToSkip && _Reader.NextResult();
_Index++) ;
// Container used to move 1 full row from the result set being read
// to the one being sent, sized to the number of fields being read
Object[] _TempRow = new Object[_Reader.FieldCount];
while (_Reader.Read())
{
_Reader.GetValues(_TempRow); // read all columns
_ResultSet.SetValues(_TempRow); // set all columns
SqlContext.Pipe.SendResultsRow(_ResultSet); // send row
}
}
catch
{
throw;
}
finally
{
if(SqlContext.Pipe.IsSendingResults)
{
SqlContext.Pipe.SendResultsEnd(); // close out result set being sent
}
if(_Reader != null && !_Reader.IsClosed)
{
_Reader.Dispose();
}
_Command.Dispose();
if (_Connection != null && _Connection.State != ConnectionState.Closed)
{
_Connection.Dispose();
}
}
return;
}
}
T-SQL test proc:
USE [tempdb]
SET ANSI_NULLS ON;
IF (OBJECT_ID('dbo.MultiResultSetTest') IS NOT NULL)
BEGIN
DROP PROCEDURE dbo.MultiResultSetTest;
END;
GO
CREATE PROCEDURE dbo.MultiResultSetTest
AS
SET NOCOUNT ON;
SELECT 1 AS [ResultSet], 'asa' AS [test];
SELECT 2 AS [ResultSet], NEWID() AS [SomeGUID], GETDATE() AS [RightNow];
EXEC sp_who2;
SELECT 4 AS [ResultSet], CONVERT(MONEY, 131.12) AS [CashYo];
GO
EXEC tempdb.dbo.MultiResultSetTest;
To do:
Adjust _ResultSetsToSkip as appropriate. If you only want the first result set, simply remove both _ResultSetsToSkip and the for loop.
Define _ResultSet as appropriate
Set _Command.CommandText to be "spDebuggerViews_GetStuckWorkflowInstances"
Create the necessary parameters via SqlParameter (i.e. #workflowSpaceId='00000000-0000-0000-0000-000000000000',#pageNum=1,#pageSize=100000,#orderByColumn=N'fldid',#sortOrder=1,#workflowInstanceId=0,#stuckInstanceType=1,#createdDateFrom='1900-01-01 00:00:00',#createdDateTo='9999-01-01 23:59:59',#updatedDateFrom='1900-01-01 00:00:00',#updatedDateTo='9999-01-01 23:59:59')
If needed, add input parameters to the SQLCLR proc so that they can be used to set the values of certain SqlParameters
Then use as follows:
INSERT INTO #stalledp
(RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC Get3rdResultSetFromGetStuckWorkflowInstances;
There is a way to get the first record set but the others, I'm afraid, you're out of luck.
EXEC sp_addlinkedserver #server = 'LOCALSERVER', #srvproduct = '',
#provider = 'SQLOLEDB', #datasrc = ##servername
SELECT * FROM OPENQUERY(LOCALSERVER, 'EXEC testproc2')
EDIT: If you only need to check the other result set for columns to be not null you could predefine the expected results sets like so:
EXEC testproc2 WITH RESULT SETS (
(a VARCHAR(MAX) NOT NULL, b VARCHAR(MAX) NOT NULL),
(a VARCHAR(MAX) NOT NULL)
);
If the query within the stored procedure returns null values a exception is raised at that point in procedure. This will only work on sql server 2012 and upwards though.

Dapper and mssql using stored procedure returning meaningful error

I have a stored procedure inserts a row, and some conditions returns result set or single error code but when I use dapper return always same return class. so I couldn't understand If code gives me error or message rather than successful result set.
public static List<Result> Results(int Id)
{
using (IDbConnection connection = BL.DataProvider.OpenConnection())
{
return connection.Query<Result>("SearchResultGet", new { Id = Id }, commandType: CommandType.StoredProcedure).ToList();
}
}
ALTER PROCEDURE SearchResultGet
#Id int
AS
IF(id != 0)
SELECT * FROM XX WHERE Id = Id
ELSE
SELECT -1
codes are just sample, doesn't have any meaning.
There is no ORM/micro-ORM API that is going to like this; having a select -1 for one set of cases is just ... not pleasant. Options:
change the sproc to not do that - just run the regular select that returns zero rows
add the logic to the Results method instead (or in addition to) the sproc - i.e. check whether Id is zero in the C#
use a return -1 rather than a select -1 (although note that dapper doesn't make it trivial to capture return values)
use a sql error (raiserror)

Why does Entity Framework throw an exception when changing SqlParameter order?

Im using entity framework 4.3 code first for calling stored procedure the way i call the stored procedure is like this:
var parameters = new[]
{
new SqlParameter("member", 1),
**new SqlParameter("Code","0165210662660001"),**
new SqlParameter("PageSize", 1),
new SqlParameter("PageNumber",1)
};
var result = context.Database.SqlQuery<resultClass>(
"mySpName #member, #Code, #PageSize,#PageNumber" parameters).ToList();
It gets executed on the SqlServer and I get the result.
But if I change the order of the paramaters like this:
var result = context.Database.SqlQuery<resultClass>("mySpName #Code, #member,#PageSize,#PageNumber" parameters).ToList();
var parameters = new[]
{
**new SqlParameter("Code","0165210662660001"),**
new SqlParameter("Member", 1),
new SqlParameter("PageSize", 1),
new SqlParameter("PageNumber",1)
};
I got an error like this :
Error converting data type nvarchar to int
The stored procedure is like this :
ALTER PROCEDURE [c].[mySpName]
#Member INT ,
#Code VARCHAR (50) ,
#PageSize INT ,
#PageNumber INT
AS
Why do i get this order?
Is it important to keep parameters order?
What can i do so that I can call a stored procedure without being concerned about parameters order?
============ i find a workaround and it works perfectly ============
public class blahContext<T>
{
int i = 0;
public IEnumerable<T> ExecuteStoreQuery(string SPname, SqlParameter[] parameters)
{
using (var context = new CADAContext())
{
string para = string.Join(", ", (from p in parameters
where !"NULL".Equals(p.Value)
select string.Concat(new object[] { "#", p.ParameterName, "={", this.i++, "}" })).ToList<string>());
object[] x = (from p in parameters
where !"NULL".Equals(p.Value)
select p.Value).ToArray<object>();
return context.Database.SqlQuery<T>(SPname + " " + para, x).ToList();
}
}
It's not because of the parameter order in your parameters object - it's because in your second code snippet you're explicitly passing the #Code value as the first parameter when the SP is expecting a Member INT value.
var result = context.Database.SqlQuery<resultClass>("mySpName #Code, #member,#PageSize,#PageNumber" parameters).ToList();
...you're passing in "0165210662660001" as the first parameter and the conversion to INT is failing.
The order of your parameters in your parameters object is irrelevant as EF (ADO.NET actually) will map those parameters to the #parametername values in your query string. So the new SqlParameter("Code","0165210662660001") will be mapped into the #Code position in your query - which int the second code snipped is actually the position for the Member value as expected by the SP.
However... you can execute a SP using named parameters as well and in that case you can pass the parameters to the SP in any order as below:
db.Database.SqlQuery<resultClass>("mySpName PageNumber=#PageNumber,Code=#Code,PageSize=#PageSize,Member=#member", parameters).ToList();
You see that I'm not passing the params to the SP in the order they were defined [by the SP] but because they're named I don't have to care.
For different ways of passing params see: This Answer for some good examples.

Resources