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
Related
I need to run three Insert queries in SQL Server 2008 via stored procedure and expected three OUTPUT values to read in C#. In following Stored Procedure, my first query only runs and remain I am getting Null error
Cannot insert the value NULL into column
'AssessmentElectronicSignatureID'
USE [myDB]
GO
/****** Object: StoredProcedure [dbo]. [p_assessment_dfn_statementAnswer_insert] Script Date: 10/05/2015 13:24:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[p_assessment_dfn_statementAnswer_insert]
#StatementID AS bigint,
#StaffID AS int,
#AssessmentID As bigint,
#StatementText AS nvarchar(MAX),
#StatementDate AS Date,
#StatementAnswerID AS bigint OUTPUT,
--
#SignatureCheck AS bit,
#SignatureDate AS Date,
#ElectronicSignatureID AS bigint OUTPUT,
--
#AssessmentElectronicSignatureID AS bigint OUTPUT
AS
SET NOCOUNT ON
SET XACT_ABORT ON
-- local variables
DECLARE #l_object AS SYSNAME = OBJECT_NAME(##PROCID)
,#l_error_msg AS NVARCHAR(2000)
BEGIN TRY
BEGIN TRAN
INSERT INTO [adb_TestDb].[dbo].[Assessment_Statement_Answer]
([StatementID],[StaffID],[AssessmentID],[StatementText],[Date])
VALUES (#StatementID, #StaffID, #AssessmentID, #StatementText, #StatementDate)
SELECT #StatementAnswerID = SCOPE_IDENTITY();
IF(#StatementAnswerID>0)
BEGIN
INSERT INTO [adb_TestDb].[dbo].[Assessment_ElectronicSignature]([AssessmentID],[ElectronicSignatureCheck],[SignatureDateAndTime])
VALUES (#AssessmentID, #SignatureCheck,#SignatureDate)
SELECT #ElectronicSignatureID = SCOPE_IDENTITY();
END
IF(#ElectronicSignatureID>0)
BEGIN
INSERT INTO [adb_TestDb].[dbo].[AssessorSignature]([AssessmentElectronicSignatureID],[StatementAnswerID],[AssessorID])
VALUES(#ElectronicSignatureID, #StatementAnswerID, #AssessmentID)
SELECT #AssessmentElectronicSignatureID = SCOPE_IDENTITY();
END
COMMIT TRAN
--RETURN SCOPE_IDENTITY();
END TRY
BEGIN CATCH
-- rollback any open/uncomitted transactions
IF XACT_STATE() IN ( -1, 1) ROLLBACK TRANSACTION
-- return an error containing the object, error number and error description
SELECT #l_error_msg = 'Error number : ' + CAST(ERROR_NUMBER()AS VARCHAR) + '. ' + ERROR_MESSAGE()
RAISERROR (#l_error_msg,16,1)
END CATCH
There is a known bug with SCOPE_IDENTITY(); Occurs occasionally when triggers are used. Google for the occurances if you want to dig deep. Or...
Try changing things like
SELECT #StatementAnswerID = SCOPE_IDENTITY();
to
SELECT #StatementAnswerID = ##IDENTITY;
Or
SET #StatementAnswerID = ##IDENTITY;
and other similar assignments. I think the problem here is causing because of being the #StatementAnswerID as Null.
I have a database which stores information about a library (books, authors & categories).
But I can't get my stored procedure to work for inserting data. The stored procedure itself executes fine, but when I perform a test, it simply doesn't add anything to the database. Can anyone see what I'm missing?
This is my stored procedure (for category):
USE MyLibrary
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'CategoryInsert' AND TYPE = 'P')
BEGIN
DROP PROC CategoryInsert
END
GO
CREATE PROCEDURE CategoryInsert
(
#Id int out,
#Name nvarchar(255),
#InsertedBy nvarchar(120),
#InsertedOn datetime
)
AS
DECLARE #CurrentId int
SELECT #CurrentId = Id FROM Category WHERE lower(#Name) = lower(#Name)
IF #CurrentId IS NOT NULL
BEGIN
SET #Id = -100
RETURN
END
INSERT INTO Category
(
Name,
InsertedBy,
InsertedOn
)
VALUES
(
#Name,
#InsertedBy,
#InsertedOn
)
SET #Id = SCOPE_IDENTITY()
GO
This is my test:
USE MyLibrary
GO
DECLARE #NewId int
DECLARE #date datetime
SET #date = getdate()
EXEC CategoryInsert #NewId, 'Testing', 'AL', #date
SELECT #NewId
GO
This line:
SELECT #CurrentId = Id FROM Category WHERE lower(#Name) = lower(#Name)
IF #CurrentId IS NOT NULL
The equality check will always return true because you're essentially comparing WHERE 1 = 1, which means that #CurrentID will always have a value and thus your stored procedure will always return before the INSERT happens.
I am trying to retrieve data from my database procedure but I'm not sure why I'm getting a return value of -1 when a value of 1 or 0 is supposed to be returned. I feel as thought everything is being passed in correctly and the procedure is running well. But I could be wrong.
I pass an object with the name of "Status" of type int into my database procedure db.proc_CsStatus and db.proc_GhStatus. During the debugger though I get "r" a value of -1.
My Controller:
public ActionResult Index()
{
ViewBag.CsStatus = GhCsStatusProvider.GetCsStatus();
ViewBag.GhStatus = GhCsStatusProvider.GetGhStatus();
return View();
}
My provider has these two functions:
public static int GetGhStatus()
{
using (Entities db = new Entities())
{
System.Data.Objects.ObjectParameter s = new System.Data.Objects.ObjectParameter("Status", typeof(int));
int r = db.proc_CsStatus(120, s);
return r;
}
}
public static int GetCsStatus()
{
using (Entities db = new Entities())
{
System.Data.Objects.ObjectParameter s = new System.Data.Objects.ObjectParameter("Status", typeof(int));
int r = db.proc_CsStatus(120, s);
return r;
}
}
Here are my database procedures:
For proc_GhStatus
USE [DATABASE_GH]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[proc_GhStatus]
-- Add the parameters for the stored procedure here
#TimeLimit Int,
#Status Int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
-- Declare variables.
DECLARE #LastUpdate Int
-- Calculate the LastUpdate.
SELECT #LastUpdate = DATEDIFF(second, Timestamp, CURRENT_TIMESTAMP)
FROM Heartbeat
WHERE Id=2
-- Compare it to the TimeLimit.
IF #LastUpdate > #TimeLimit SELECT #Status = 0
ELSE SELECT #Status = 1
END
GO
For CsStatus
USE [DATABASE_CS]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[proc_CsStatus]
-- Add the parameters for the stored procedure here
#TimeLimit Int,
#Status Int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
-- Declare variables.
DECLARE #LastUpdate Int
-- Calculate the LastUpdate.
SELECT #LastUpdate = DATEDIFF(second, Timestamp, CURRENT_TIMESTAMP)
FROM Heartbeat
WHERE Id=1
-- Compare it to the TimeLimit.
IF #LastUpdate > #TimeLimit SELECT #Status = 0
ELSE SELECT #Status = 1
END
GO
In the stored procedure you are not return the status. Therefore you can't set the status in the code like below.
int r = db.proc_CsStatus(120, s);
This will only return the status of the stored procedure execution. -1 means there were some errors in stored procedure execution. Simplest way would be remove the out parameter and return the #status from sp. Then you should be able to retrieve the values the way you have done.
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
-- Declare variables.
DECLARE #LastUpdate Int
-- Calculate the LastUpdate.
SELECT #LastUpdate = DATEDIFF(second, Timestamp, CURRENT_TIMESTAMP)
FROM Heartbeat
WHERE Id=1
-- Compare it to the TimeLimit.
IF #LastUpdate > #TimeLimit SELECT #Status = 0
ELSE SELECT #Status = 1
// Below line shoud be added.
RETURN #Status
Also make sure to set right return type in the DBModel as mentioned in other answers.
The possible problem is that the imported SP in EF is not told to return a value. To check do the followings:
Open the .edmx file.
Open Model Browser.
Brows to DBModel.
Under Function Imports section find your SP and right click on it then open Properties.
Check whether the Return Type is set to None or not.
If it is not change it to appropriate value.
UPDATE: my code is behaving as expected by there was a typo in the stored procedure that was the reason it was failing.
I can't seem to figure out why or how to fix this because I am not getting any errors what I am getting is the return value is 0 which means fail.
Here is my .net code:
SqlParameter returnValue= new SqlParameter("returnValue", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
cmd.ExecuteNonQuery();
result = Convert.ToInt32(returnValue.Value); //1 success and 0 failed
My stored procedure:
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
SET NOCOUNT ON
DECLARE #Result int
SET #Result = 0
UPDATE Employee
SET name = #name
WHERE employee_id = #employee_id
IF (##rowcount = 1)
BEGIN
SET #Result = 1
END
SET NOCOUNT OFF
RETURN #Result
END
So if I just execute the stored procedure from SQL Server Management Studio, it does update my row successfully without any error
EXEC EmployeeUpdate 34,'John John'
Return Value = 1
Replace the following
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
SET NOCOUNT ON
With Following
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
SET NOCOUNT OFF
SET NOCOUNT ON is indicating that number of rows effect by T-SQL will
not be returned
SET NOCOUNT OFF mean that number of rows effect by
T-SQL will be returned.
I would suggest to remove returnValue parameter altogether and just use the return value of ExecuteNonQuery() method instead:
int rowsAffected = cmd.ExecuteNonQuery();
result = rowsAffected == 1 ? 1 : 0;
Stored procedure:
CREATE PROCEDURE EmployeeUpdate
#employee_id BIGINT,
#name nvarchar(250)
AS
BEGIN
UPDATE Employee
SET name = #name
WHERE employee_id = #employee_id
END
Say we have stored procedure(s) performing simple operations like this:
CREATE PROCEDURE [dbo].[AddNewAuthorReturnID]
(
#Author_Name VARCHAR(MAX),
#Author_ID int OUTPUT
)
AS
SET NOCOUNT OFF;
BEGIN
INSERT INTO AUTHORS (#Author_Name)
VALUES (#Author_Name)
SET #Author_ID = SCOPE_IDENTITY()
SELECT #Author_ID
END
In the above procedure, the returned id is an indication of successful operation.
Consider the equivalent with DELETE.
CREATE PROCEDURE [dbo].[DeleteAuthor]
(
#Author_ID int
)
AS
SET NOCOUNT OFF;
BEGIN
DELETE FROM AUTHORS
WHERE
(Author_ID = #Author_ID)
END
How can we know the operation was
successful and the AUTHORS record was
succesfully removed if we use the above
procedure ?
With an update operation?
You could select ##rowcount
It will show you the rows affected.
e.g
CREATE PROCEDURE [dbo].[DeleteAuthor]
(
#Author_ID int
)
AS
SET NOCOUNT OFF;
BEGIN
DELETE FROM AUTHORS
WHERE
(Author_ID = #Author_ID)
SELECT ##ROWCOUNT
END
This can be applied to update too.
CREATE PROCEDURE [dbo].[UpdateAuthor]
(
#Author_ID int
)
AS
SET NOCOUNT OFF;
BEGIN
UPDATE AUTHORS
SET AuthorName = 'John'
WHERE
(Author_ID = #Author_ID)
SELECT ##ROWCOUNT
END
Alternatively you could use ##Error and raise an error id ##rowcount > 1 (if you only wanted to update one row).
e.g
CREATE PROCEDURE [dbo].[DeleteAuthor]
(
#Author_ID int
)
AS
SET NOCOUNT OFF;
BEGIN
DELETE FROM AUTHORS
WHERE
(Author_ID = #Author_ID)
IF ##ROWCOUNT <>1
BEGIN
RAISERROR ('An error occured',10,1)
RETURN -1
END
END
As Giorgi says this will be returned as a returncode.
You can to return ##ROWCOUNT to determine if your last statement affected any record.
You can return value from stored procedure using return statement. The ##ERROR variable is equal to zero if there was no error.
##ERROR
CREATE PROCEDURE [dbo].[DeleteAuthor]
(
#Author_ID int
)
AS
SET NOCOUNT OFF;
BEGIN
DELETE FROM AUTHORS
WHERE
(Author_ID = #Author_ID)
Return ##ERROR
END