I am trying to call a stored procedure using C# EF6 to bring back data. I have tried to run the stored procedure in SQL management studio and it seems to work fine, however when I try to run it in my application I get an error saying "Must declare the scalar variable "#devID"
Here is part of my method in my application calling the stored procedure
public IHttpActionResult GetMetrics(int deviceID, string attribute, string startDate)
{
if (deviceID == 0)
{
return NotFound();
}
var metrics = db.Database.SqlQuery<Metrics>("GetMetrics #devID, #MetricType, #startTime", deviceID, attribute, startDate).ToList();
and here is my stored procedure:
ALTER PROCEDURE [dbo].[GetMetrics]
-- Add the parameters for the stored procedure here
#devID int,
#MetricType nvarchar(20),
#startTime nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT *
FROM dbMetrics
WHERE deviceID = #devID and MetricType = #MetricType and timeStamp >= #startTime
ORDER BY timeStamp
END
As per the documentation, if you want to use named parameters, you need to pass SqlParameter objects like this:
var metrics = db.Database.SqlQuery<Metrics>("GetMetrics #devID, #MetricType, #startTime",
new SqlParameter("devID", deviceID),
new SqlParameter("MetricType", attribute),
new SqlParameter("startTime", startDate)
).ToList();
Related
alter procedure [dbo].[XXX]
(
#vendorworksationID uniqueidentifier ,
#sdate date,
#edate date,
#total int out
)
begin
select #total = COUNT(*)
from AdvertisedCampaignHistory a
where
CAST(a.CreationDate AS DATE) BETWEEN CAST(#sdate as DATE) AND CAST(#edate as DATE)
and a.CampaignID in (select cc.BCampaignID
from BeaconCampaign cc, VendorWorkStation vw
where cc.VendorWorkStationID = vw.VendorWorkStationID
and VendorID = #vendorworksationID)
return #total
end
The above code shows the stored procedure that return an integer value from SQL Server
ObjectParameter Output = new ObjectParameter("total", typeof(Int32));
var resBC = this.Context.getTotalSentBeaconCampaign(VendorWorkstationID, sdate,edate,Output).FirstOrDefault();
The above code shows how I am passing parameters and retrieving the value on the C# side
While running the code I am getting following error
The data reader returned by the store data provider does not have
enough columns for the query requested.
What could be the possible cause for this error?
Entity Framework cannot support Stored Procedure Return scalar values out of the box.To get this to work with Entity Framework, you need to use "Select" instead of "Return" to return back the value.
More Ref : http://www.devtoolshed.com/using-stored-procedures-entity-framework-scalar-return-values
My stored procedure is working correctly. However, I am not able to retrieve it.
My current function to retrieve the value from the stored procedure is:
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);//.ToString());
return r;
}
}
I don't mind if this is changed or not used at all. I am currently getting a "r" value of -1 when I am expecting a 0 or 1.
Here is my stored procedure:
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
Any input is much appreciated!!!
After executing your procedure, your the ObjectParameter s will contain the value. Your procedure call will not return it. The value you are looking for should be able to be found in s.Value.
Try the following:
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 (int)s.Value;
}
}
The value which you are returning(r) is the number of rows affected by your procedure.
More Info:
Behind the scenes, your procedure is doing something along the lines of the following:
return base.ExecuteFunction("proc_CsStatus", input, output);
ObjectContext.ExecuteFunction() returns the number of rows affected by the call.
I have a SQL stored procedure for updating my table. But when executing the query via C#, xslt the one of the columns deleted from the table.
My stored procedure is
ALTER PROCEDURE [dbo].[kt_editingnotes]
(#NOTE NVARCHAR (512),
#ITEMNUMBER NVARCHAR (512),
#ACCOUNT NVARCHAR (512),
#CODE NVARCHAR(512)
)
AS
UPDATE NOTES
SET TXT = #NOTE
WHERE NOTESRECID = (SELECT ISP_EFAVORITLINE.ROWNUMBER
FROM ISP_EFAVORITLINE
WHERE ISP_EFAVORITLINE.ACCOUNT = #ACCOUNT
AND ISP_EFAVORITLINE.ITEMNUMBER = #ITEMNUMBER
AND ISP_EFAVORITLINE.CODE = #CODE)
return
and I am calling it like this:
ExecStoredProcedure('kt_editingnotes', concat('#ITEMNUMBER:', $ITEMNUMBER,', #ACCOUNT:', $ACCOUNT,', #CODE:', $CODE))
What is the problem? Can anyone help?
editingI noticed in the ExecStoredProcedure that you execute the procedure 'kt_deletenotes' instead of 'kt_editingnotes'. Try changing the line where you call your procedure to call the correct procedure.
ExecStoredProcedure('kt_editingnotes', concat('#ITEMNUMBER:', $ITEMNUMBER,', #ACCOUNT:', $ACCOUNT,', #CODE:', $CODE))
I write this stored procedure but I am returning all sql queries to site code and I have a little problem to convert this query. I insert data in one table then insert it in another table with key that is generated in first table. I don't know what is the best way to write this from site code. To make three methods or what?
#m_UserId uniqueidentifier,
#m_WispTypeId int,
#m_CreatedOnDate datetime,
#m_PrivacyTypeId int,
#m_WispText nvarchar(200)
AS
SET XACT_ABORT, NOCOUNT ON
DECLARE #starttrancount int
BEGIN TRY
SELECT #starttrancount = ##TRANCOUNT
IF #starttrancount = 0
BEGIN TRANSACTION
DECLARE #wispId int
INSERT INTO dbo.tbl_Wisps
(UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
VALUES
(#m_UserId,#m_WispTypeId,#m_CreatedOnDate,#m_PrivacyTypeId,#m_WispText)
SELECT #wispId = SCOPE_IDENTITY()
INSERT INTO dbo.tbl_CommentableEntity
(ItemId)
VALUES
(#wispId)
DECLARE #ceid int
select #ceid = SCOPE_IDENTITY()
UPDATE dbo.tbl_Wisps SET CommentableEntityId = #ceid WHERE WispId = #wispId
IF #starttrancount = 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 AND #starttrancount = 0
ROLLBACK TRANSACTION
RAISERROR ('Error in adding new wisp', 16, 1)
END CATCH
There are a number of ways to use the OUTPUT clause. The following pattern may work for you:
insert dbo.tbl_CommentableEntity (ItemId)
select wispId from (
insert dbo.tbl_Wisps (UserId,WispTypeId,CreatedOnDate,PrivacyTypeId,WispText)
output inserted.wispId
values (#m_UserId, #m_WispTypeId, #m_CreatedOnDate, #m_PrivacyTypeId, #m_WispText)
) as ins
If you want to do it in code, I would split it into several methods and have the save methods return the identity. Then, you can just create a method that encompasses all three queries, and which emulates through code the same logic that is in the stored procedure
public int SaveThis()
{
return -1 //return identity
}
public int SaveThat(int thisID)
{
return -2 //return identity
}
public void SaveThisAndThat()
{
int thisID = this.SaveThis();
int thatID = this.SaveThat(thisID);
//so on and so forth
}
I have a procedure with a single select statement. I am need to create some 50 procedures like the one below..
create procedure foo1 as
select cityid, cityname from footballteam
the footballteam will be common in all my procedures, Instead of creating 50 single procedures, I want to code like below and send 3 parameters from my c# page
create procedure foo1 (#id bigint, #name varchar(50), #param bigint)as
select #id, #name from footballtem where #id =#param
can i pass like this in sql server ?/ How to do like this
will I am able to do procedure overloading in sql server, some time I need to pass only two parameters and i want to get a particular value , I will pass three or more parameters ....
For a pure TSQL answer:
create table footballtem(id int identity(1,1),cityid int, cityname varchar(50))
go
insert footballtem(cityid, cityname) values (123, 'abc')
insert footballtem(cityid, cityname) values (456, 'def')
go
create procedure foo1 (#id sysname, #name sysname, #param bigint) as
declare #sql nvarchar(100) = 'select ' + QUOTENAME(#id) + ','
+ QUOTENAME(#name) + ' from footballtem where '
+ QUOTENAME(#id) + '=#param'
exec sp_ExecuteSql #sql, N'#param bigint', #param
go
exec foo1 'cityid','cityname',123
(credit is due to Mikael Eriksson re QUOTENAME)
Note that QUOTENAME makes the #name and #id injection safe.
Note also, though, that the varying parameter (#param) is safe from injection - we don't need to validate that anywhere; and that this will allow query-plan re-use via sp_ExecuteSql
No; that would do a comparison on the parameter values, and return the parameter values. To do that, you would have to substitute the values at the caller, for example:
string idColumn = "id", nameColumn = "name";
string tsql = string.Format(#"
create procedure foo1 (#param bigint)
as select [{0}], [{1}] from footballtem where [{0}]=#param", idColumn,nameColumn);
and have 50 SPs; you can do the same in TSQL, using sp_ExecuteSQL against an already replaced string, but IMO it would be better to do this at the app tier than inside the database.
Also; question whether you really need stored procedures... that one isn't really going to help much; a parameterised TSQL query is much simpler, just as fast, and easier to deploy.
I'm not sure if I understand you correctly, but you can specify a default value for a stored procedure parameter in T-SQL. So you can omit it while calling.
CREATE PROCEDURE Proc1 #param1 int, #param2 int = -1 AS SELECT case when #param2=-1 then somefield else #param2 end as column from sometable where somekeyfield=#param1; GO
(assuming MS SQL Server)
MS SQL server does not support procedure overloading (as Oracle Does) but does support input and output parameters like this:
create procedure foo1 (
#param bigint
, #id bigint out
, #name varchar(50) out
)as
select
#id = fbt.id
,#name = fbt.name
from
footballteam fbt
where fbt.id =#param
#id and #name have to be passed in as null value output paramters of the correct type. After execution (cmd.executeNonQuery) you can inspect the command object to get the new parameter values back out.
I am not sure I am reading your question correctly, but if I am then this should get what you want..
*Adding better code sample after question *
//_assumes the following using statements at the top of code file:_
//using System.Data;
//using System.Data.SqlClient;
public string getTeam(int CityID)
{
string name;
using (var cmd = new SqlCommand("foo1",new SqlConnection("myConnectionStringGoesHere")))
{
cmd.Parameters.Add(new SqlParameter("#param", CityID));
cmd.Parameters.Add(new SqlParameter("#id", SqlDbType.BigInt){Direction=ParameterDirection.Output});
cmd.Parameters.Add(new SqlParameter("#name", SqlDbType.VarChar,50) { Direction = ParameterDirection.Output });
cmd.Connection.Open();
cmd.ExecuteNonQuery();
name = cmd.Parameters["#name"].Value.ToString();
cmd.Connection.Close();
}
return name;
}
I think you were asking for the following:
create procedure foo1 (#id bitint out, #name bigint out, #param bigint)
as
select #id=cityid, #name=cityname from footballteam where teamname = #param
But your question makes it seem like you are trying to dynamically change the column names per query.
There is a way to do overloading on MSSQL. Here how it goes:
For example we have a sp_Personel procedure which takes personel type as parameter and lists personel of that type.
CREATE PROCEDURE [dbo].[sp_Personel]
#PersonelType int
AS
SELECT Name, JoinDate, PersonelType, Salary
FROM Personel
WHERE PersonelType = #PersonelType
END
Now, you want another procedure which will be for personel join dates.
CREATE PROCEDURE [dbo].[sp_Personel];2
#JoinDate datetime
AS
SELECT Name, JoinDate, PersonelType, Salary
FROM Personel
WHERE JoinDate <= #JoinDate
END
To call second procedure from management studio;
[dbo].[sp_Personel];2 N'9/26/2010'