Get value output from SQL Server stored procedure into variable - c#

This seems to be a simple question but nevertheless I haven't found an answer yet.
I have the following stored procedure
CREATE PROCEDURE [dbo].[AllocateId]
AS
BEGIN TRANSACTION
UPDATE TOP(1) IdReservation
SET IsAllocated = 1
OUTPUT DELETED.Id
WHERE IsAllocated = 0
COMMIT TRANSACTION
GO
It's been used in C# + EF code without a problem via ExecuteFunction of ObjectContext
ObjectResult<int> objectResult = ExecuteFunction<int>("AllocateId");
However when I try to call it directly from SQL script it doesn't seem to work
declare #Id int
EXEC #Id = [dbo].[AllocateId]
#Id is always 0. How do I get the value into #Id variable in sql script?

Procedure return value is different from result set(s) returned by that procedure. Your stored procedure returns a result set and does not return a return value (which ends up being null, which gets converted to 0 implicitly upon exiting the procedure).
To get the resultset your existing procedure retuns, you need insert ... exec:
declare #t table (id int);
insert into #t
exec [dbo].[AllocateId];
If you want to return a value as a return value as well, you should amend you stored procedure:
CREATE PROCEDURE [dbo].[AllocateId]
AS
BEGIN TRANSACTION
declare #id int;
UPDATE TOP(1) IdReservation
SET #id = Id, IsAllocated = 1
OUTPUT DELETED.Id
WHERE IsAllocated = 0
COMMIT TRANSACTION
return #id;
Then it will work in the way you describe in the question.

Related

How can i get the row id that inserted via stored procedure?

Model model=new Model();
model.id=0;
model.name="";
model.surname="";
db.Model.Add(model);
db.SaveChanges();
int id_returned=model.id;
This block gives me the id field of the inserted row.
But i use stored procedure for this insert process.
Model model=new Model();
model.id=0;
model.name="";
model.surname="";
int returned_id2=db.Sp_Model_insert(model.name, model.surname);
this block inserts the row. returned_id2 returns -1.
How can i get the row id that inserted via Sp ?
Here is my Stored Procedure:
USE [KayaShop]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [KS_ACCOUNTS].[SP_AccountModules_Insert](
#Area nvarchar(50),
#Controller nvarchar(50),
#Action nvarchar(50),
#SubAction nvarchar(50),
#Name nvarchar(50),
#TopName nvarchar(50),
#Level int,
#Visible int,
#Clickable int,
#HomePage int,
#Icon nvarchar(20),
#Status int
)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [KS_ACCOUNTS].[AccountModules]
([Area]
,[Controller]
,[Action]
,[SubAction]
,[Name]
,[TopName]
,[Level]
,[Visible]
,[Clickable]
,[HomePage]
,[Icon]
,[Status])
VALUES
(#Area,
#Controller,
#Action,
#SubAction,
#Name,
#TopName,
#Level,
#Visible,
#Clickable,
#HomePage,
#Icon,
#Status)
END
SELECT SCOPE_IDENTITY()
Add this after the insert query in your stored procedure
Multiple ways:
SCOPE_IDENTITY() - https://msdn.microsoft.com/en-us/library/ms190315.aspx - Returns the last single IDENTITY value in the current session's current scope.
##IDENTITY - https://msdn.microsoft.com/en-us/library/ms187342.aspx - Returns the last single IDENTITY value in the current session (regardless of scope).
INSERT INTO ... VALUES ... OUTPUT - https://msdn.microsoft.com/en-us/library/ms177564.aspx - outputs all inserted values, including IDENTITY values, this is the only way to retrieve IDENTITY values when your INSERT statement will insert multiple rows.
As your stored procedure only seems to insert a single row, you should be fine with SCOPE_IDENTITY.
Note that if all your stored procedure does is INSERT you probably don't need a stored procedure, your database client code should perform the INSERT directly.
Note that you should not use the RETURN keyword to return the IDENTITY value to the caller, you should use output parameters - a stored procedure's return-value is intended to convey status information and it is restricted to just an int value (e.g. return 0 for success).
I added these lines to the end of my sp:
SELECT #Id =SCOPE_IDENTITY()
RETURN
and at my code side:
int Id = 0;
ObjectParameter prm = new ObjectParameter("Id", typeof(int));
DB.SP_AccountModules_Insert(DTO.Area, DTO.Controller, DTO.Action, DTO.SubAction, DTO.Name, DTO.TopName, DTO.Level, DTO.Visible, DTO.Clickable, DTO.HomePage, DTO.Icon, DTO.Status, prm);
Id = Convert.ToInt32(prm.Value);
return Id;
i send and out parameter from my code to my sp, then i assign the last inserted id to my parameter and return it to my code. thats it.
Thank you for all help.

Why I get exception when I call stored procedure?

I am using Entity Framework 6 and Microsoft SQL Server 2012.
Here is my stored procedure:
ALTER PROCEDURE SPDeleteRegion
#siteId int,
#regionId int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #isDeleted BIT
IF EXISTS (SELECT 1 FROM SiteObjects WHERE SiteRegionId = #regionId)
BEGIN
SET #isDeleted = 0 ; --not deleted
RETURN #isDeleted;
END
ELSE
BEGIN
--do what needs to be done if not
DELETE FROM SiteRegions
WHERE Id = #regionId;
SET #isDeleted = 1; -- deleted
RETURN #isDeleted;
END
END
Here how I call the stored procedure in C#:
var t = _context.Database.SqlQuery<bool>("SPDeleteRegion #siteId, #regionId",
new SqlParameter("#siteId", siteId),
new SqlParameter("#regionId", regionId));
On the line of code above I get this exception:
The data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types.
Any idea why I get the excewption and how to fix it?
Your procedure doesn't selecting anything. Change it like this:
ALTER PROCEDURE SPDeleteRegion
-- Add the parameters for the stored procedure here
#siteId int,
#regionId int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE
#isDeleted BIT
IF EXISTS (SELECT 1 FROM SiteObjects WHERE SiteRegionId = #regionId)
BEGIN
SET #isDeleted = 0 ; --not deleted
SELECT #isDeleted [IsDeleted]; --HERE
END
ELSE
BEGIN
--do what needs to be done if not
DELETE FROM SiteRegions WHERE Id = #regionId;
SET #isDeleted = 1;--deleted
SELECT #isDeleted [IsDeleted]; -- AND HERE
END
END

Getting an simple value with Entity Framework Stored Procedure

I have a Stored Procedure and turns me an integer. I want to take and use that integer but get an error like:
'System.Data.Objects.ObjectResult1[System.Nullable1[System.Int32]]'
type object couldn't assign to 'System.IConvertible'.
Here is my Stored Procedure:
CREATE PROC prDetectMurderer(#carId INT)
AS BEGIN
SET NOCOUNT ON
SELECT TOP 1 DriverId FROM EventTable
WHERE CarId = #carId
AND Damage = 'false'
ORDER BY EventId DESC
SET NOCOUNT OFF
END
And my c# code:
int sofor = Convert.ToInt16(entity.prDetectMurderer(11));
How can I solve it ?
This answer https://stackoverflow.com/a/35832669/3572241 shows how to get an int from a stored procedure, using EF.

Stored Procedure CRUD MySQL

I have a problem with a procedure that I'm developing in MySQL, this is my first time. A few months ago I made a small CRUD (select, insert, update) in MSSQL, and only sends the required data.
create procedure sp_Bodegas (#Opcion varchar(10), #CodBodega int = null, #NomBodega varchar(75) = null, #DirBodega varchar(150) = null, #EstBodega bit = null)
as
begin
set nocount on
if (#Opcion='SELECT')
begin
select cod_Bodega as CodBodega, nom_Bodega as NomBodega, dir_Bodega as DirBodega, est_Bodega as EstBodega from inv_Bodegas
end
if (#Opcion='INSERT')
begin
insert into inv_Bodegas (cod_Bodega, nom_Bodega, dir_Bodega, est_Bodega) values (#CodBodega, #NomBodega, #DirBodega, #EstBodega)
end
if (#Opcion='UPDATE')
begin
update inv_Bodegas set nom_Bodega = #NomBodega, dir_Bodega = #DirBodega where cod_Bodega = #CodBodega
end
set nocount off
end;
But a few days ago I started to work with MySQL and try to do the same procedure but this can not use variables such as '#NomBodega = Null' for not sending any data required option. then create input variables to receive the data, but now there are many parameters that have to send every time you run the procedure.
create procedure sp_Bodegas (in Opcion varchar(10), in CodBodega int, in NomBodega varchar(75), in DirBodega varchar(150), in EstBodega bit)
begin
if Opcion = 'SELECT' then
select cod_Bodega as CodBodega, nom_Bodega as NomBodega, dir_Bodega as DirBodega, est_Bodega as EstBodega from inv_Bodegas;
end if;
if Opcion = 'INSERT' then
insert into inv_Bodegas (cod_Bodega, nom_Bodega, dir_Bodega, est_Bodega) values (#CodBodega, #NomBodega, #DirBodega, #EstBodega);
end if;
if Opcion = 'UPDATE' then
update inv_Bodegas set nom_Bodega = #NomBodega, dir_Bodega = #DirBodega where cod_Bodega = #CodBodega;
end if;
end;
Wanted to know how I can make it work so very similar in my application, I am using aspx and EF for my database.
Thanks.
You have declared the variable as NomBodega but when you are using it in your procedure you use #NomBodega.
The #NomBodega would only be required if you passed in an out parameter to select the value after the procedure has run.
Thanks for your help, but i was very busy.
After read a lot of SP MYSQL i find is not possible so. i gona send every value.
Is it possible to have a default parameter for a mysql stored procedure?

How should I handle the retrieval of a recently inserted record ID so that it may be inserted into another table?

I have a Vendor object within my View Model. When I insert this vendor record into the database, I want to retrieve the ID of this Vendor because it will be used as a foreign key on another table immediately after (in a different sproc). I'm attempting to do this with test as the ID I need to retrieve. The following code doesn't work because proc_amcInsertApplicationServerRelationship expects an integer, but test is of type of Object Parameter.
I guess my questions are:
Am I approaching this correctly? If not, what would be a better approach? Also, based on my current approach, is there something simple I'm overlooking that I could do to get this to work? Here's my code (sorry if I'm not providing enough detail):
[HttpPost]
public ActionResult Create(ApplicationViewModel applicationViewModel)
{
try
{
// TODO: Add insert logic here
ObjectParameter test = new ObjectParameter("ID", typeof (int));
var vendorID = db.proc_amcInsertNewVendor(applicationViewModel.Vendor.Company, applicationViewModel.Vendor.StreetAddress, applicationViewModel.Vendor.SecondaryStreetAddress,
applicationViewModel.Vendor.City, applicationViewModel.Vendor.State, applicationViewModel.Vendor.ZipCode, applicationViewModel.Vendor.PhoneNumber,
applicationViewModel.Vendor.Website, test);
foreach (var serverID in applicationViewModel.ServerIDs)
{
db.proc_amcInsertApplicationServerRelationship(test, serverID);
}
return RedirectToAction("Index");
}
catch (Exception exception)
{
return View();
}
}
EDIT: Per Request, here's my stored procedure.
#Company varchar(100)
,#StreetAddress varchar(100)
,#SecondaryStreetAddress varchar(50)
,#City varchar(50)
,#State varchar(50)
,#ZipCode varchar(10)
,#PhoneNumber varchar(15)
,#Website varchar(200)
,#ID int = NULL OUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO [dbo].[amc_Vendors]
(
[Company]
,[StreetAddress]
,[SecondaryStreetAddress]
,[City]
,[State]
,[ZipCode]
,[PhoneNumber]
,[Website]
)
VALUES
(
#Company
,#StreetAddress
,#SecondaryStreetAddress
,#City
,#State
,#ZipCode
,#PhoneNumber
,#Website
)
SET #Id = SCOPE_IDENTITY()
END
GO
In your SP after insert statement. Use
Select ##IDENTITY As ReturnedId
In your service code, do:
int Id=db.proc_amcInsertApplicationServerRelationship(serverId).FirstOrDefault().ReturnedId;
Use this Id for your further processing.
There is solution to this but you need to make sure for the followings:
-What you can try with your current code is return Identity of recently added Items with ##Identity in SQL procedure and get the same from command as return value or as output parameter.
Use the returned value and sent the same in next operation.
But as far as my expertise says this would be not good option. Since you are having dependencies for Query execution, You need to implement Transaction as well.
you can handle them at both database and Application level
Use Single SP to insert records in both table with Transaction or
Use Transaction class at Application level in C#
Hope these would be helpful
Do Following:
In Your SP:
CREATE PROCEDURE dbo.YourSPName
#Param1 varchar(156),
#Id Int OUTPUT
AS
SET NOCOUNT ON;
SELECT #Id = ##IDENTITY
In your C# code:
var outputParameter = new ObjectParameter("Id", typeof(int));
context.YourSPName("ParamValue", outputParameter);
Console.WriteLine(outputParameter.Value);

Categories

Resources