Bug in MVC Core 2 - Stored Procedures returns null - sql-server

how do I report a bug to MVC Core2 team, the stored procedure Output Parameter returns null,
Here is my code
var p = new SqlParameter
{
ParameterName = "token",
DbType = System.Data.DbType.String,
Size = 100, Value = "Sarah",
Direction = System.Data.ParameterDirection.Output
};
var z = p.SqlValue;
var resp = await _context.Database.ExecuteSqlCommandAsync("exec dbo.yourstoredprocedure {0}, {1}","test", p);
var y = p.SqlValue;
var x = p.Value;
resp is always -1 and x and y are both null, the stored procedure is simply
create PROCEDURE [dbo].[yourstoredprocedure]
( #varone nvarchar(max),
#vartwo nvarchar(50) OUTPUT)
AS
insert into test (two, three) select #varone, #vartwo'
SET #vartwo = scope_identity()
return #vartwo;

Like I said in the comments, your SP is full of Syntax errors. It should probably look more like this:
CREATE PROCEDURE [dbo].[yourstoredprocedure] #varone nvarchar(max),
#vartwo nvarchar(50),
#varfour int OUTPUT AS --What happened to #varthree ?
INSERT INTO test (two, three)
VALUES (#varone, #vartwo);
SET #varfour = SCOPE_IDENTITY();
GO

Related

SQL Server stored procedure with default values

I Have SQL Server stored procedure with ~100 parameters, with default values. I have to pass only 3 of them. Is it possible to use StoredProcedureQuery? Now if I have procedure:
create procedure MyProc(#Param1 varchar(30) = "test", #Param2 smallint = 1, #Param3 char = 'a', #Param4 char = 'b',
#Param5 varchar(50) = "test", #Param6 tinyint = 7, #Param7 varchar(3) = "tes", #Param8 varchar(3) = "ADS",
#Param9 varchar(50) = "TEST", #Param10 varchar(8) = "TEST", #Param11 varchar(222) = "TEST")
and executing procedure like this:
StoredProcedureQuery storedProcedureQuery = entityManagerFactory.createEntityManager()
.createStoredProcedureQuery("MyProc");
query.registerStoredProcedureParameter("Param9", String.class, ParameterMode.IN)
.setParameter("Param9", "test9");
query.registerStoredProcedureParameter("Param10", Character.class, ParameterMode.IN)
.setParameter("Param10", "test10");
query.registerStoredProcedureParameter("Param11", String.class, ParameterMode.IN)
.setParameter("Param11", "test11");
Unfortenatly value "test9" goes to #Param1, "test10" goes to #Param2 and "test11" goes to #Param3.
Is it possible to pass parameters by name, not by position?
It is possible to pass parameters by name using JPA and SQL Server using NativeQuery.
Query query = entityManagerFactory.createEntityManager().createNativeQuery("""
DECLARE #return_value int
EXEC #return_value = [dbo].[MyProc]
#Param9 = :Param9,
#Param10 = :Param10,
#Param11 = :Param11
""");
query.setParameter("Param9", "test9");
query.setParameter("Param10", "test10");
query.setParameter("Param11", "test11");

How to execute a stored procedure in kotlin

I would like to run the master.sys.fn_varbintohexsubstring sql procedure in kotlin. If I run that procedure in Datagrip it looks like this:
begin
declare #fsetprefix bit = null
declare #pbinin varbinary(max) = null
declare #startoffset int = 0
declare #cbytesin int = 0
declare #result nvarchar(max)
exec
#result = sys.fn_varbintohexsubstring
#fsetprefix,
#pbinin,
#startoffset,
#cbytesin
select #result as result
end
The only thing I would like to change is #pbinin with the value HASHBYTES('SHA1', CONVERT(varchar(255), ?)+'DEL'+?). The value of the first questionmark is the password in clear text, the second one is the salt.That works fine. But how do I call that procedure in kotlin? I tried this
val pStmt = con?.prepareCall("\\{call master.sys.fn_varbintohexsubstring(0,HASHBYTES('SHA1', CONVERT" + "(varchar(255), ${user.clearPassword})+'DEL'+${user.salt}),1,0)\\}")
pStmt?.registerOutParameter("result", Types.VARCHAR)
val cursor = pStmt?.executeQuery()
if (cursor != null) {
while (cursor.next()) {
val result = cursor.getString("result")
}
}

How to retrieve stored procedure return value with Dapper

I have a stored procedure of this form:
CREATE PROCEDURE AddProduct
(#ProductID varchar(10),
#Name nvarchar(150)
)
AS
SET NOCOUNT ON;
IF EXISTS (SELECT TOP 1 ProductID FROM Products
WHERE ProductID = #ProductID)
RETURN -11
ELSE
BEGIN
INSERT INTO Products ([AgentID], [Name])
VALUES (#AgentID, #Name)
RETURN ##ERROR
END
I have this C# to call the stored procedure, but I can't seem to get a correct value form it:
var returnCode = cn.Query(
sql: "AddProduct",
param: new { #ProductID = prodId, #Name = name },
commandType: CommandType.StoredProcedure);
How can I ensure that the returnCode variable will contain the value returned from either the RETURN -11 or the RETURN ##ERROR lines?
To enable use of the RETURN statement in SQL the C# becomes...
var _params = new DynamicParameters{ #ProductID = prodId, #Name = name };
_params.Add(
name: "#RetVal",
dbType: DbType.Int32,
direction: ParameterDirection.ReturnValue
);
var returnCode = cn.Execute(
sql: "AddProduct",
param: _params,
commandType: CommandType.StoredProcedure);
return _params.Get<int>("#RetVal");
It's not the implementation I was hoping for, but it works.
I suggest you use SELECT to return the values from your stored procedure. Also you should specify a return type on the dapper call:
RETURN -11
becomes
SELECT -11
and the dapper call becomes:
var returnCode = cn.Query<int>(..
I have implemented this pattern several times and it works as expected.

Use a stored procedure to get a list of nvarchar(20) values as a parameter

I'm developing a SQL Server 2012 stored procedure.
I need to return a list of nvarchar(20) values, and I don't know how can I do it. I have tried this:
Using a Table-Valued Parameters but it must be READONLY.
Doing a select to return that list. But stored procedures only
returns INT values.
Any idea?
UPDATE:
This is what I have done:
CREATE PROCEDURE [dbo].[GetAggregationChildren]
#parentCode nvarchar(20),
#codeLevel tinyint output,
#returnValue int output
AS
declare #childsLevelCount tinyint
, #invalidChildCodesCount int;
set nocount on;
-- ======== VALIDATION ==========
if NULLIF(#parentCode, '') IS NULL
begin
set #returnValue = -19;
return NULL; -- Parameter null or empty.
end
-- Check if parent exists in AGGREGATIONS table.
if not exists (Select top 1 CODE from AGGREGATIONS where CODE = #parentCode)
begin
set #returnValue = -11;
return NULL;
end
set #childsLevelCount = (select count(c.CODE_LEVEL) from CODES c where c.CODE in (Select CODE from AGGREGATION_CHILDS where PARENT_CODE = #parentCode) group by c.CODE_LEVEL);
-- If this aggregation has children codes with different values, it is an error.
if (#childsLevelCount > 1)
begin
set #returnValue = -201;
return NULL;
end
-- =========== CODE =============
set #returnValue = 0;
set #codeLevel = (select c.CODE_LEVEL from CODES c where c.CODE in (Select CODE from AGGREGATION_CHILDS where PARENT_CODE = #parentCode) group by c.CODE_LEVEL);
select CODE from AGGREGATION_CHILDS where PARENT_CODE = #parentCode;
But, I have no idea about how to return the result of this select:
select CODE from AGGREGATION_CHILDS where PARENT_CODE = #parentCode;
This stored procedure returns this on SQL Server Management Studio:
It is also returning a 0. I thought that the stored procedure is going to return the select result only.
I need the result in a parameter because I going to use in a SQLCommand like this one:
SqlParameter childsParam = new SqlParameter();
childsParam.ParameterName = "#childs";
childsParam.SqlDbType = System.Data.SqlDbType.Structured;
childsParam.Direction = System.Data.ParameterDirection.Input;
childsParam.Value = tvp;
parameters = new List<SqlParameter>();
parameters.Add(childsParam);
SqlConnection connection =
_context.Database.Connection as SqlConnection;
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = storedProcedureName;
cmd.CommandType = CommandType.StoredProcedure;
if (parameters != null)
cmd.Parameters.AddRange(parameters.ToArray());
cmd.Connection = connection;
cmd.ExecuteNonQuery();
connection.Close();
Stored procedure returns only Integer?
No this is not 100% true. If you are using RETURN to return the values from your stored procedure then your statement is true else it is false.
If you want to return string from your stored procedure then you can use SELECT like this:
CREATE PROCEDURE myProc
AS
BEGIN
SELECT 'test'
END
And to return multiple values you can use it like
CREATE PROCEDURE myProc
#Value1 varchar(20) OUTPUT,
#Value2 varchar(20) OUTPUT
AS
SELECT #Value1 = 'test1', #Value2 = 'test2'
and call it like
DECLARE #Value1 varchar(20), #Value2 varchar(20)
exec myProc #Value1 OUTPUT, #Value2 OUTPUT
SELECT #Value1, #Value1
Stored procedures return the type of the field in the SELECT statement. You can use CAST and CONVERT to change the types. For example:
SELECT CAST(field AS NVARCHAR(20))
With table value parameters you can set the field type on creation:
CREATE TYPE JobSpecifications AS TABLE
(JobName VARCHAR(50), AvailableDate Date );
you can use a temporary table to recuperate your list from the stored procedure, like the example below :
create proc Test
AS BEGIN
SELECT CAST('jkj' AS NVARCHAR(20)) value
END
DECLARE #tmp TABLE(value nvarchar(20))
INSERT INTO #tmp EXEC GhaziTest
SELECT * from #tmp

Procedure with update new information

So I have been working on simple procedure for school that asks me to:
(Create a stored procedure called UpdateProduct that takes in a required Product ID parameter and optionally any other one or more fields in the Product table. Then the proc will update any fields passed in but leave any other fields as they were.
If executed like this: UpdateProduct #productID = 1, #name = ‘Steel Ball Bearing’; Only the name should change, all other fields should still contain the value there before the procedure
was called)
This is what I have but still I cant seem to get it to work properly. I am going nuts because I have been trying to figure this out for several days. Any help pointing out my mistake would be awesome.
USE AdventureWorks2012
GO
CREATE PROC UpdateProduct2
#ProductID INT ,
#Name nvarchar (50)= ISNULL,
#ProductNumber nvarchar (25) =ISNULL,
#Color nvarchar (15)=ISNULL
AS
BEGIN
UPDATE [Production].[Product]
SET
Name = ISNULL (#Name,Name),
ProductNumber = ISNULL (#ProductNumber,ProductNumber),
Color = ISNULL (#Color, Color)
WHERE #Name=Name
END
I think your where clause should be:
WHERE ProductID = #ProductID;
rather than
WHERE #Name=Name
Also you need to use NULL rather than ISNULL to set the parameter defaults:
CREATE PROC UpdateProduct2
#ProductID int,
#Name nvarchar(50) = NULL,
#ProductNumber nvarchar(25) = NULL,
#Color nvarchar(15) = NULL
AS
BEGIN
UPDATE [Production].[Product]
SET Name = ISNULL (#Name,Name),
ProductNumber = ISNULL (#ProductNumber,ProductNumber),
Color = ISNULL (#Color, Color)
WHERE ProductID = #ProductID;
END
EDIT
To answer the question about specifying NULL as the default, yes there is a reason, it allows you to call the procedure without passing the parameter.
Take the following two procedures:
CREATE PROCEDURE dbo.P1 #p1 VARCHAR(20), #p2 VARCHAR(20)
AS
BEGIN
SELECT P1 = #p1, P2 = #p2;
END;
GO
CREATE PROCEDURE dbo.P2 #p1 VARCHAR(20) = NULL, #p2 VARCHAR(20) = NULL
AS
BEGIN
SELECT P1 = #p1, P2 = #p2;
END;
The first using no default, and the latter with NULL as the default. The only way to call the first procedure is to send all parameters, e.g.
EXECUTE dbo.p1;
EXECUTE dbo.p1 #P2 = 'TEST';
EXECUTE dbo.p1 #P1 = 'TEST';
Will generate the following errors:
Msg 201, Level 16, State 4, Procedure P1, Line 0
Procedure or function 'P1' expects parameter '#p1', which was not supplied.
Msg 201, Level 16, State 4, Procedure P1, Line 0
Procedure or function 'P1' expects parameter '#p1', which was not supplied.
Msg 201, Level 16, State 4, Procedure P1, Line 0
Procedure or function 'P1' expects parameter '#p2', which was not supplied.
Whereas this:
EXECUTE dbo.p2;
EXECUTE dbo.p2 #P2 = 'TEST';
EXECUTE dbo.p2 #P1 = 'TEST';
Will generate:
P1 P2
NULL NULL
P1 P2
NULL TEST
P1 P2
TEST NULL

Resources