I am trying to execute stored procedure from bcontext.Database.SqlQuery using EF5.
It is throwing an error must declare the scalar variable '#custid'
var results = _MiscContext.Database.SqlQuery<int>(
"exec sp_GetStaff #custid",
customerNumber).ToList<int>();
SP returns 1 if customerNumber is staff otherwise it return empty row.
ALTER PROCEDURE [dbo].[sp_GetStaff]
#custid varchar(12)
AS
BEGIN
SET NOCOUNT ON;
SELECT
1 AS [C1]
FROM [dbo].[Staff] with (nolock)
WHERE [CUSTOMER_ID] = #custid
END
How to manage this?
Since you're using named parameters, you have to specify the matching name for the parameter you're passing.
var results = _MiscContext.Database.SqlQuery<int>(
"exec sp_GetStaff #custid",
new SqlParameter("custid", customerNumber)).ToList<int>();
Try
var results = _MiscContext.Database.SqlQuery<int>(
"exec sp_GetStaff {0}",
customerNumber).ToList();
Related
I'm passing a string variable to an IN Clause in sql (Stored Procedure). When declaring and setting the variable in sql I get back all the data that is required. But when setting the variable from c# I'm only receiving data based on the first status within that paramater.
I've got a function to split the statuses in the paramater list to retrieve the records:
ALTER FUNCTION [dbo].[fnSplit](
#sInputList VARCHAR(8000)
, #sDelimiter VARCHAR(10) = ';'
) RETURNS #List TABLE (item VARCHAR(8000))
BEGIN
DECLARE #sItem VARCHAR(8000)
WHILE CHARINDEX(#sDelimiter,#sInputList,0) <> 0
BEGIN
SELECT
#sItem=RTRIM(LTRIM(SUBSTRING(#sInputList,1,CHARINDEX(#sDelimiter,#sInputList,0)-1))),
#sInputList=RTRIM(LTRIM(SUBSTRING(#sInputList,CHARINDEX(#sDelimiter,#sInputList,0)+LEN(#sDelimiter),LEN(#sInputList))))
IF LEN(#sItem) > 0
INSERT INTO #List SELECT #sItem
END
IF LEN(#sInputList) > 0
INSERT INTO #List SELECT #sInputList
RETURN
END
My stored procedure is built like this:
ALTER procedure [dbo].[Get_RequestsAtEachStage]
(#managerRef int,
#status varchar(20))
as
BEGIN
WITH MaxStatusDate
as
(
select rs.requestID,rs.status from (
SELECT requestID,MAX([DateCreated]) AS MaxDate
FROM [LoanRequest].[dbo].[requestStatus]
GROUP BY RequestID) maxg
inner join [LoanRequest].[dbo].[requestStatus] rs on maxg.requestid = rs.requestid and maxg.MaxDate = rs.DateCreated
)
SELECT lr.ID, lr.serialNo, lr.model, lr.clientName, lr.address, lr.telephone, lr.contactName,
lr.swop, lr.substitueOfGoods, lr.printFunction, lr.copyFunction, lr.scanFunction,
lr.faxFunction, lr.controller, lr.controllerEmailAddress,
ml.Name, wl.Location, rt.requestType AS RequestTypeName, rs.status
FROM [dbo].[loanRequest] lr
INNER JOIN [dbo].[managersList] ml ON lr.managerRef = ml.ID
INNER JOIN [dbo].[warehouseList] wl ON lr.warehouseID = wl.ID
INNER JOIN [dbo].[requestType] rt ON lr.requestType = rt.ID
INNER JOIN MaxStatusDate rs ON lr.ID = rs.requestID
WHERE (#managerRef is null or lr.managerRef = #managerRef) AND rs.status IN (SELECT item FROM [dbo].[fnSplit](#status, ';'))
END
Based on the page the user access it will send through the appropriate statusses and retrieve the necessary records.
Setting the paramaters in sql as follows works perfect, I retrieve all the records:
DECLARE #managerRef INT
DECLARE #status NVARCHAR(100)
SET #managerRef = NULL
SET #status = 'Allocated;Readings Updated'
But, when I send it through c# within a string, it only retrieves records with the status of Allocated.:
string status = "Allocated;Readings Updated";
DataTable dtDevices = d.PopulateDevicesApproval(managerRef, status);
My method to retrieve the data from sql:
string filterstring = "";
filterstring = "Get_RequestsAtEachStage ";
cn = new SqlConnection(GetConnectionString());
SqlCommand myCmd = new SqlCommand(filterstring, cn);
myCmd.CommandType = CommandType.StoredProcedure;
cn.Open();
myCmd.Parameters.AddWithValue("#managerRef", managerRef);
myCmd.Parameters.AddWithValue("#status", status);
DataTable dt = new DataTable();
dt.Load(myCmd.ExecuteReader());
return dt;
Is there anything I am doing wrong?
--------- EDIT -----------
Running SELECT item FROM [dbo].fnSplit results from both c# and sql
Returning results from c#:
And returning results from sql:
I always use to return the number of rows ,use a foreach loop.
In a part of the project I need to get a procedure with dynamic data.
Procedure code:
ALTER procedure [dbo].[abcde]
#fldStatusIdString nvarchar(max)
as
begin
declare #Query nvarchar(max)
set #Query = '
SELECT a.fldEstateId, a.fldEstateTitle, a.fldThumbnail,a.fldPrice,fldAcceptDate
FROM (
SELECT dbo.tblImages.fldEstateId, dbo.tblImages.fldThumbnail, dbo.tblEstates.fldEstateTitle,
dbo.tblEstates.fldPrice, dbo.tblEstates.fldAcceptDate, ROW_NUMBER() OVER (PARTITION BY dbo.tblImages.fldEstateId
ORDER BY dbo.tblEstates.fldAcceptDate) AS RowNumber
FROM dbo.tblImages INNER JOIN dbo.tblEstates ON dbo.tblEstates.fldEstateId = dbo.tblImages.fldEstateId
WHERE (dbo.tblEstates.fldStatusOfAccept = 1)'
set #Query +='and (fldStatusId in('+#fldStatusIdString+'))
) AS a
WHERE a.RowNumber = 1
order by fldEstateId
'
execute sp_executesql #Query
end
When i use above procedure, can not use ToList in foreach loop.
If the normal procedure is not a problem, but if i use a above way(input data with the number of variables), I get an error.
C# Code:
List<Join_Estates_Images_Model> ListAll = new List<Join_Estates_Images_Model>();
foreach (var item in db.abcde(fldStatusIdString).ToList())
{
Join_Estates_Images_Model _entity = new Join_Estates_Images_Model();
_entity.fldEstateId = item.fldEstateId;
_entity.fldEstateTitle = item.fldEstateTitle;
_entity.fldThumbnail = item.fldThumbnail;
_entity.fldPrice = Convert.ToDecimal(item.fldPrice);
_entity.fldAcceptDate = item.fldAcceptDate;
ListAll.Add(_entity);
}
return ListAll;
Error message:
Error 14 'int' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?)
I used 'using System.Linq'
Another way of doing it will be to pass the comma delimited list to the variable and handle it inside the procedure something like ......
Also you do not need dynamic sql here.....
ALTER procedure [dbo].[abcde]
#fldStatusIdString nvarchar(max)
as
begin
DECLARE #xml XML;
SET #xml = N'<t>' + REPLACE(#fldStatusIdString,',','</t><t>') + '</t>';
SELECT a.fldEstateId, a.fldEstateTitle, a.fldThumbnail,a.fldPrice,fldAcceptDate
FROM (
SELECT dbo.tblImages.fldEstateId
, dbo.tblImages.fldThumbnail
, dbo.tblEstates.fldEstateTitle
, dbo.tblEstates.fldPrice
, dbo.tblEstates.fldAcceptDate
, ROW_NUMBER() OVER (PARTITION BY dbo.tblImages.fldEstateId
ORDER BY dbo.tblEstates.fldAcceptDate) AS RowNumber
FROM dbo.tblImages
INNER JOIN dbo.tblEstates
ON dbo.tblEstates.fldEstateId = dbo.tblImages.fldEstateId
WHERE (dbo.tblEstates.fldStatusOfAccept = 1)
and (fldStatusId in(
SELECT r.value('.','varchar(MAX)') as item
FROM #xml.nodes('/t') as records(r)
)
)
) AS a
WHERE a.RowNumber = 1
order by fldEstateId
end
I was facing same kind of problem with entity framework. Entity framework always gives a integer resultset with dynamic query. Just follow below steps
Update your model
Drop your procedure from .edmx.
Drop result set and related function as well.
Update your procedure. Generate result set with non dynamic query.
Again add procedure in your entity.
I've had a search round the internet and cannot find anything that directly matches what I'm after....
I have a stored procedure that returns a fixed set of columns (let's say ColumnA, ColumnB and ColumnC) and then additionally returns an indeterminate number / signature of additional columns (maybe ColumnD, ColumnE and ColumnF, or ColumnF, ColumnP, ColumnT and ColumnW).
The dynamic part of the query is determined by an Id param to the proc.
Unfortunately I am not in control of the schema and it has been poorly designed to have a very large number of unrelated columns added to the end (and they keep adding them), rather than having an additional table(s) to store this effectively.
As a result, I am unable to return a determinate set of columns at compile time, so LINQ to SQL cannot determine the return type of the stored procedure.
Do I have any other options, or ways I can get around this? Here's an example of what I am doing below. Can I re-write this to work with LINQ to SQL? I am writing the application with C# and SQL Server 2008 if that helps.
Thanks.
CREATE PROCEDURE [Foo].[GetBar]
(
#Id INT,
#FooVar VARCHAR(50),
#BarVar DATE
)
AS
BEGIN
CREATE TABLE #TempTbl
(
[ColumnName] VARCHAR(50)
)
INSERT #TempTbl EXEC [Foo].GetColumnNames #Id
DECLARE #ColumnNameList NVARCHAR(max)
SET #ColumnNameList = ''
SELECT #ColumnNameList = COALESCE(#ColumnNameList + '],[', '') + ColumnName FROM #TempTbl
DROP TABLE #TempTbl
SELECT #ColumnNameList = #ColumnNameList + ']'
SELECT #ColumnNameList = SUBSTRING(#ColumnNameList, 3, LEN(#ColumnNameList) )
DECLARE #FixedColumns VARCHAR(200)
DECLARE #SelectQuery NVARCHAR(max)
DECLARE #WhereQuery VARCHAR (100)
DECLARE #FullQuery NVARCHAR(max)
DECLARE #ParamaterDef nvarchar (100)
DECLARE #Foo VARCHAR(50)
DECLARE #Bar DATE
SET #FixedColumns = N'[ColumnA], [ColumnB], [ColumnC], '
SET #SelectQuery = N'SELECT ' + #FixedColumns + #ColumnNameList + N' FROM [Foo].[FooBar] '
SET #WhereQuery = N'WHERE [Foo] = #Foo AND [Bar] = #Bar'
SET #FullQuery = #SelectQuery + #WhereQuery
SET #ParamaterDef = N'#Foo VARCHAR(50), #Bar DATE'
EXECUTE sp_executesql #FullQuery, #ParamaterDef, #Foo = #FooVar, #Bar = #BarVar
END
Can you not just use a SQL Data Adapter that fills a DataSet? You could then use LINQ to DataSet and perform all of your LINQ operations:
DataTable yourDataTable = ds.Tables["TableName"];
var query =
from yourDataTable in yourDataTable.AsEnumerable()
select new
{
NewField = yourDataTable.Field<int>("ColumnName"),
NewField2 = yourDataTable.Field<string>("ColumnName2"),
};
MSDN (LINQ to DataSet)
MSDN (Single table queries using LINQ to DataSet
I am trying to create a MySql stored procedure through C#. I have created some other as well but when I try to execute the Query via MySqlCommand.ExecuteNonQuery its throws a exception that you query syntax is not compatible. Here is the exception message:
You have an error in your SQL syntax;
check the manual that corresponds to
your MySQL server version for the
right syntax to use near 'SET
VariableRecordExists = (SELECT
COUNT(*) FROM SmartCache_Sync WHERE
MachineNa' at line 10
And here I am trying to build the query string:
string sql = #"CREATE PROCEDURE SmartCache_UpdateSync
(
VariableMachineName varchar(50)
)
BEGIN
DECLARE VariableRecordExists int;
DECLARE VariableSetDate datetime;
START TRANSACTION;
SET VariableSetDate= Now()
SET VariableRecordExists = (SELECT COUNT(*) FROM SmartCache_Sync WHERE MachineName = VariableMachineName)
IF VariableRecordExists = 1
THEN
UPDATE SmartCache_Sync
SET LastUpdate = VariableSetDate
WHERE MachineName= VariableMachineName;
ELSE
INSERT INTO SmartCache_Sync
(MachineName,LastUpdate)
VALUES (VariableMachineName,VariableSetDate);
END IF;
COMMIT;
SELECT VariableSetDate;
END";
I don't know where I am making a mistake. Probably I am missing a semi colon ; somewhere or what. I would be obliged if anyone could help me.
I don't know about making queryies in c#, but normally the ; is the end of your query: so if you don't change the delimiter, you are ending your command early. normally you would do something like this:
delimiter //
CREATE PROCEDURE simpleproc (OUT param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM t;
END//
delimiter ;
from:
http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
Slightly off-topic - but...
In general, prefer "if exists (select...)" to "select count(*)..." when all you want to do is check if any rows exist. It is far cheaper than actually counting all the rows.
And secondly, it looks as though you are trying to do an "upsert", which in MySQL would be
INSERT INTO SmartCache_Sync(MachineName,LastUpdate)
VALUES (VariableMachineName,VariableSetDate)
ON DUPLICATE KEY UPDATE LastUpdate = VariableSetDate
and then you don't need the explicit transaction either.
This of course assumes that MachineName is a primary key, which I'm guessing it is.
My guess was right I was missing a ";". And honestly speaking it took me 2 hours to that out.
**
SET VariableSetDate= Now();
SET VariableRecordExists = (SELECT COUNT(*) FROM SmartCache_Sync
WHERE MachineName =
VariableMachineName);
**
Both the statements didn't have ";" at the end
CREATE PROCEDURE SmartCache_UpdateSync
(
VariableMachineName varchar(50)
)
BEGIN
DECLARE VariableRecordExists int;
DECLARE VariableSetDate datetime;
START TRANSACTION;
SET VariableSetDate= Now()
(SELECT VariableRecordExists = COUNT(*) FROM SmartCache_Sync WHERE MachineName = VariableMachineName)
IF VariableRecordExists = 1
THEN
UPDATE SmartCache_Sync
SET LastUpdate = VariableSetDate
WHERE MachineName= VariableMachineName;
ELSE
INSERT INTO SmartCache_Sync
(MachineName,LastUpdate)
VALUES (VariableMachineName,VariableSetDate);
END IF;
COMMIT;
SELECT VariableSetDate;
END";
Is it possible to send a list of IDs to a stored procedure from c#?
UPDATE Germs
SET Mutated = ~Mutated
WHERE (GermID IN (ids))
This may be a dirty hack, but you can create a temp table and then join to it from within your stored procedure (assuming they are accessed during the same connection). For example:
CREATE TABLE #ids (id int)
INSERT INTO #ids VALUES ('123') -- your C# code would generate all of the inserts
-- From within your stored procedure...
UPDATE g
SET Mutated = ~Mutated
FROM Germs g
JOIN #ids i ON g.GermID = i.id
You could try what i have made do with:-
Create a function called Split_String
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
CREATE FUNCTION [dbo].[Split_String]
(
#MyString varchar(5000)
)
RETURNS #Results TABLE
(
Value varchar(1000)
)
AS
BEGIN
DECLARE #Pos int
DECLARE #StrLen int
DECLARE #MyLen int
DECLARE #MyVal varchar
SET #pos = 1
SET #MyLen = 1
WHILE #MyString <> ''
BEGIN
SET #MyLen = charindex(',',#MyString)
IF #MyLen = 0 SET #MyLen = Len(#MyString)
INSERT #Results SELECT replace(substring(#MyString, #pos, #MyLen),',','')
SET #MyString = SUBSTRING(#MyString,#MyLen+1,len(#MyString))
END
RETURN
END
Then when you use IN() use in the following fashion with a comma separated string:-
SELECT * FROM [youDataBase].[dbo].[Split_String] (<#MyString, varchar(5000),>)
According to This article, you could try the Table Value Parameter.
Yep, you can use a chunk of XML to build your list of ID's. Then you can use OPENXML and select from that record set.
Look up OPENXML, sp_preparexmldocument, sp_removexmldocument