I'm not geting the right results from a stored procedure - c#

I have this strored procedure that I use to get the sum of Amount from 3 tables.
The problem is that I'm using Linq to Sql and when I put this procedure on my .dbml file, it has a
ISingleResult(GetSurplusDataForConsolidationReportResult) and I can't get the sums I want.
I'm receiving an empty ReceivablesSurplus list.
Any ideas?
ALTER PROCEDURE [dbo].[GetSurplusDataForConsolidationReport]
#ID INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT SUM(RB.[Amount])
FROM [DBO].[ReceivablesSurplus] RB
WHERE RB.[Cycle] = #ID
SELECT SUM(DL.[Amount])
FROM [DBO].[DilutionsSurplus] DL
WHERE DL.[Cycle] = #ID
SELECT SUM(AC.[Amount])
FROM [DBO].[AccountablesSurplus] AC
WHERE AC.[Cycle] = #ID
END
this is my .dbml code
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.GetSurplusDataForConsolidationReport")]
public ISingleResult<GetSurplusDataForConsolidationReportResult> GetSurplusDataForConsolidationReport([global::System.Data.Linq.Mapping.ParameterAttribute(Name="ID", DbType="Int")] System.Nullable<int> iD)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), iD);
return ((ISingleResult<GetSurplusDataForConsolidationReportResult>)(result.ReturnValue));
}

You should just be able to use .ToList() on the value (as ISingleResult implements IEnumerable) to the calling line of code, and then you can get at the separate result sets that are returned from the sproc.
e.g
var results = dataContext.GetSurplusDataForConsolidationReport(123).ToList<int>(); // list of sums

Related

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.

Retrieving Database procedure value with Provider

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.

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);

Entity Framework - stored procedure return value

I am trying to get the return value of a stored procedure. Here is an example of such a stored procedure:
select
Name,
IsEnabled
from
dbo.something
where
ID = #ID
if ##rowcount = 0
return 1
return
This is a simple select. If 0 rows are found, my result set will be null, but I will still have a return value.
This is a bad example, as this is a select, so sure I could find if 0 rows were returned. However, on an Insert, delete, or other calls, we need this return value to know if there was a problem. I have been unable to find a way to get this return value. I can get output values, I can get result sets, but no return value.
I can get the return value if I call SQL manually, or even if I run a SqlCommand using the Entity Framework, but this is not what I want to do.
Has anyone ever been able to get the return value from a stored procedure using Entity Framework?
Thanks for the help!
I guess support of stored procedure return values depends on version of Entity framework. Although directly returning value didn't work for me I managed to get value using OUTPUT stored procedure parameter. Example:
USE [YOUR_DB_NAME]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[TestReturnValue]
#InputValue int = 0,
#Result int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #Result = #InputValue
RETURN(#InputValue);
END
This is test code:
void TestReturnValue()
{
using (var db = new YourDBContext())
{
var result = new System.Data.Objects.ObjectParameter("Result", 0);
Console.WriteLine("SP returned {0}", db.TestReturnValue(123, result));
Console.WriteLine("Output param {0}", result.Value);
}
}
And this is output:
SP returned -1
Output param 123
As you see directly returned value output some rubbish but OUTPUT parameters works!
This article provides general info on two ways of returning values from SP
Hope this helps
No. Entity Framework doesn't have rich stored procedure support because its an ORM, not a SQL replacement.
As you have already discovered, if you need to use less common (more advanced?) features of stored procedures, you'll have to use good old fashioned ADO.NET.
You must use the "Context.Database.SqlQuery",and specify the output type of the stored procedure
var spReturnVaue = Context.Database.SqlQuery<Type>("[schema].YourSp").FirstOrDefault();
int firstId = Context.Database.SqlQuery<int>("[dbo].GetFirstId").FirstOrDefault();
Based on Hadi Salehy's answer, I wrote this code and works for me.
My SP
CREATE PROCEDURE [schema].[ProcedureName]
#param1 int,
#param2 varchar(20),
#param3 varchar(50)
AS
UPDATE Table1
SET Field2 = #param2, Fiedl3 = #param3
WHERE (Field1 = #param1)
SELECT ##ROWCOUNT;
My C# code.
int quantity = await _context.Database.ExecuteSqlRawAsync("[schema].[ProcedureName] {0}, {1}, {2}", myModel.Param1, myModel.Param2, myModel.Param3);
In order to get the interested result in EF, you should return a same structure (not 1 and Name, IsEnabled)
In this query you should return '',0 for example instead of 1 in the if condition:
select
Name,
IsEnabled
from
dbo.something
where
ID = #ID
if ##rowcount = 0
return '',0

Get value output from SQL Server stored procedure into variable

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.

Categories

Resources