Failed to get result of stored procedure - c#

I created a procedure that returns the ID of the Question based on the input text
ALTER PROCEDURE [dbo].[GetQuestionIDbyTekst]
(
#Tekst nvarchar(100)
)
AS
DECLARE #QuestionID int
SELECT QuestionID
FROM dbo.Questions
WHERE Tekst = #Tekst
RETURN #QuestionID
and I have a problem in getting the value of the QuestionID:
public static int getQuestionID(Question p)
{
using (Entities dm = new Entities())
{
return dm.GetQuestionIDbyTekst(p.Tekst);
}
}

Make the #QuestionID as Output parameter. Also you need to assign the result to #QuestionID
ALTER PROCEDURE [dbo].[GetQuestionIDbyTekst]
(
#Tekst nvarchar(100),
#QuestionID INT OUTPUT
)
AS
BEGIN
DECLARE #QuestionID int
SELECT #QuestionID = QuestionID FROM dbo.Questions WHERE Tekst = #Tekst
END

please try this:
ALTER PROCEDURE [dbo].[GetQuestionIDbyTekst]
(
#Tekst nvarchar(100)
)
AS
-- DECLARE #QuestionID int
SELECT QuestionID
FROM dbo.Questions
WHERE Tekst = #Tekst
-- RETURN #QuestionID

You can use your variant of the stored procedure.
And if you use ADO.NET and want to get return value, try this:
SqlConnection con = new SqlConnection(#"Data Source=localhost\***;Initial Catalog=***;Integrated Security=True;Persist Security Info=False;");
con.Open();
SqlCommand cmd = new SqlCommand("GetQuestionIDbyTekst", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#Tekst", System.Data.SqlDbType.NVarChar).Value = "eee";
SqlParameter returnPar = new SqlParameter();
returnPar.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(retturnPar);
cmd.ExecuteScalar();
var result = returnPar.Value;
If you use Entity Framework, you may use this variant:
public static int GetQuestionIDbyTekst(string question)
{
using (var context = new EfDbContext())
{
var test = new SqlParameter("#Tekst", question);
var resultParam = new SqlParameter("#result", SqlDbType.Int);
resultParam.Direction = ParameterDirection.Output;
context.Database.ExecuteSqlCommand("exec #result = [dbo].[testProc] #Tekst", resultParam, test);
return (int)resultParam.Value;
}
}

Related

How can I return a value as an OUTPUT parameter?

I'm trying to get the OUTPUT parameter to work, but for whatever reason, it's refusing to. I keep getting null as a result. If I do everything on the SQL side, it works fine. I tested it like this,
DECLARE #test INT
EXEC MyProc #number = 1, #id = #test
PRINT #test
which gave me the output exactly as I expected. I've looked over this code for an hour and it looks right. The likely cause is an ID10T error, but my brain just isn't seeing it.
public static int MyFunc(int id)
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["cnString"].ConnectionString))
{
connection.Open();
using (var cmd = new SqlCommand("dbo.MyProc", connection)
{
CommandTimeout = 120,
CommandType = CommandType.StoredProcedure
})
{
cmd.Parameters.AddWithValue("#number", SqlDbType.Int);
var param = new SqlParameter("#id", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
Debug.WriteLine(param.Value);
return Convert.ToInt32(param.Value);
}
}
}
ALTER PROCEDURE dbo.MyProc
(
#number INT ,
#id INT OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
SET #id = (
SELECT Id
FROM SomeTable
WHERE SomeValue = #number
);
RETURN;
END;
You have a simple typo ...
You are passing the value of the SqlDbType.Int that you are expecting instead of the parameter to MyFunc.
cmd.Parameters.AddWithValue("#number", SqlDbType.Int);
should be
cmd.Parameters.AddWithValue("#number", id);
You can try this :
cmd.Parameters.AddWithValue("#number", SqlDbType.Int).Value = id;
cmd.Parameters.Add(param).Value = id

Stored procedure with OUTPUT Parameter Always Returns 1 in Application Code vs SQL

In SQL Server Management Studio:
Right click the procedure
Execute
Do not enter value for the OUTPUT parameter
Enter value for another string parameter
The correct value is returned (ex: 12+)
Calling code:
DECLARE #return_value int,
#CustomerID bigint
EXEC #return_value = [dbo].[InsertCustomer]
#CustomerID = #CustomerID OUTPUT,
#Name = N'CustomerName'
SELECT #CustomerID as N'#CustomerID'
SELECT 'Return Value' = #return_value
In application code:
Run the following code
The returned value for CustomerID is always 1
Code:
ObjectParameter ob = new ObjectParameter("CustomerID", typeof(long));
var CustomerID = db.InsertCustomer(ob, "CustomerName");
I attempted to change the new ObjectParameter(,) second parameter by passing a type and often object by value (ex: 0, 1 etc) but with no avail.
What could have went wrong here?
Update:
This is how the Entity Framework procedure code look like:
public virtual int InsertCustomer(ObjectParameter customerID, string name)
{
var nameParameter = name != null ?
new ObjectParameter("Name", name) :
new ObjectParameter("Name", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("InsertCustomer", customerID, nameParameter);
}
Straight ADO:
Please refer to this link.. You need to specify your output parameter in the proc and you need to specify it in the calling code.
SqlParameter outParam = new SqlParameter("CustomerID", 0);
using (SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["StringName"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("InsertCustomer", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = CustomerName;
cmd.Parameters.Add(outParam.ParameterName, SqlDbType.BigInt).Direction = ParameterDirection.Output;
con.Open();
var CustomerID = Convert.ToInt64(cmd.Parameters["CustomerID"].Value);
}
}
Entity Framework:
Refer to this link
ObjectParameter ob = new ObjectParameter("CustomerID", 0);
// Wrong
var CustomerID = db.InsertCustomer(ob, "CustomerName");
// Right
db.InsertCustomer(ob, "CustomerName");
var CustomerID = (long)ob.Value;

The select list for the INSERT statement contains fewer items than the insert list.

Apparently the insert list contains more items than the the number of selected values but cant seem to see where that is the case. by observation they are the same unless I am missing something?
public static DateTime CreateMedicationDispenseLocationHistory( int medicationDispenseID, int locationID, int staffID, DateTime date )
{
SqlConnection connection = new SqlConnection( Utilities.DBConnectionString() );
connection.Open();
CreateMedicationDispenseLocationHistory( medicationDispenseID, locationID, staffID, date, connection, null );
connection.Close();
connection.Dispose();
return date;
}
public static DateTime CreateMedicationDispenseLocationHistory( int medicationDispenseID, int locationID, int staffID, DateTime date, SqlConnection connection, SqlTransaction transaction )
{
Locations location = new Locations();
MedicationList medication = new MedicationList();
StringBuilder sqlString = new StringBuilder();
SqlCommand command;
sqlString.Append("INSERT INTO [MedicationDispenseLocationHistory] (");
sqlString.Append("MedicationDispenseID, " );
sqlString.Append("LocationID, " );
sqlString.Append("StaffID, " );
sqlString.Append("DateTimeStamp" );
sqlString.Append(") SELECT SCOPE_IDENTITY();");
command = new SqlCommand( sqlString.ToString(), connection );
if( ( transaction != null ) ) command.Transaction = transaction;
command.Parameters.Add( "#MedicationDispenseID", SqlDbType.Int ).Value = medication.MedicationDispenseID;
command.Parameters.Add( "#LocationID", SqlDbType.Int ).Value = location.LocationID;
command.Parameters.Add( "#StaffID", SqlDbType.Int, 500 ).Value = Helper.GetValue( GlobalVariables.loggedInStaff.StaffID );
command.Parameters.Add( "#DateTimeStamp", SqlDbType.DateTime ).Value = Helper.GetDBDateValue(DateTime.Now);
//command.Parameters.Add("#stopDate", SqlDbType.DateTime).Value = Helper.GetValue(medicationDispense.StopDate);
medication.MedicationDispenseID = Convert.ToInt32( command.ExecuteScalar() );
return date;
}
Add a semicolon at the end of the INSERT INTO statement
sqlString.Append("); SELECT SCOPE_IDENTITY();");
Otherwise the following SELECT SCOPE_IDENTITY() will be interpreted as the SELECT list of values for the INSERT
INSERT INTO ....... SELECT
To complete the answer (giving credit to the authors of the comments below)
Do not forget to add the values placeholders for your parameters
sqlString.Append(") VALUES (#MedicationDispenseID,#LocationID,#StaffID,#DateTimeStamp);");
sqlString.Append("SELECT SCOPE_IDENTITY();");

Executing SQL Stored Procedure

ALTER PROCEDURE dbo.SP_InsertTicket
/*
(
#parameter1 int = 5,
#parameter2 datatype OUTPUT
)
declare #i as numeric
exec SP_InsertTicket 'asd','cd#y.com','232323','dasasd','sdasdas','01-jan-2010',#i output,'sdas','sdasd','02-jan-2010'
select #i*/
#Client_FullName varchar(30),
#Client_EmailAdd varchar(50),
#Client_Telephn varchar(15),
#Ticket_Subject varchar(50),
#Ticket_Source varchar(15),
#Ticket_CreateDate Datetime,
#Ticket_Id integer output,
#Que_Message varchar(100),
#Que_Attachment varchar(max),
#Que_UpdateDate Datetime
AS
declare #TickID integer;
/* SET NOCOUNT ON */
BEGIN
INSERT INTO tbl_Ticket (Client_FullName,Client_EmailAdd,Client_Telephn,Ticket_Subject,Ticket_Source,Ticket_CreateDate)
VALUES (#Client_FullName, #Client_EmailAdd ,#Client_Telephn,#Ticket_Subject,#Ticket_Source,#Ticket_CreateDate)
Select #TickID = MAX(Ticket_Id) from tbl_Ticket
set #Ticket_Id=#TickID
INSERT INTO tbl_TicketQuestion (Ticket_Id,Que_Message,Que_Attachment,Que_UpdateDate)
VALUES (#TickID,#Que_Message,#Que_Attachment,#Que_UpdateDate)
END
RETURN
This is my store procedure in which i need to return Ticket_Id to send it via email app
It insert records well bt not able to retirn value in DAL
Below is the code for executing stored procedure which returns value
public class cls_DAL
{
public cls_DAL()
{
//
// TODO: Add constructor logic here
//
}
static string strConn = System.Configuration.ConfigurationManager.ConnectionStrings["conString"].ConnectionString.ToString();
SqlConnection con = new SqlConnection(strConn);
SqlCommand cmd = new SqlCommand();
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
DataTable dt = new DataTable();
public int insert_NewTicket(string fullname, string emailadd, string telephone, string subject, string source, DateTime date,string Message, string attachment, DateTime updatedate)
{
try
{
con.Open();
cmd = new SqlCommand("SP_InsertTicket", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Client_FullName", fullname);
cmd.Parameters.AddWithValue("#Client_EmailAdd", emailadd);
cmd.Parameters.AddWithValue("#Client_Telephn",telephone);
cmd.Parameters.AddWithValue("#Ticket_Subject", subject);
cmd.Parameters.AddWithValue("#Ticket_Source",source);
cmd.Parameters.AddWithValue("#Ticket_CreateDate",date);
cmd.Parameters.AddWithValue("#Ticket_Id",0);
cmd.Parameters.AddWithValue("#Que_Message", Message);
cmd.Parameters.AddWithValue("#Que_Attachment", attachment);
cmd.Parameters.AddWithValue("#Que_UpdateDate",updatedate);
cmd.Parameters["#Ticket_Id"].Direction = ParameterDirection.InputOutput;
return cmd.ExecuteNonQuery();
int i = (int)cmd.Parameters["#Ticket_Id"].Value;
}
catch
{
throw;
}
finally
{
cmd.Dispose();
con.Close();
con.Dispose();
}
}
}
Its just a guess, not sure. You can give a try the following:
cmd.Parameters["#Ticket_Id"].Direction = ParameterDirection.InputOutput;
TO
cmd.Parameters["#Ticket_Id"].Direction = ParameterDirection.Output;
That won't compile you'll get unreachable code
cmd.Parameters["#Ticket_Id"].Direction = ParameterDirection.InputOutput; cmd.ExecuteNonQuery();
return (int)cmd.Parameters["#Ticket_Id"].Value;
or #Matt's solution below...
That cast is iffy as well...
And in a multi user scenario, ticketid will race.
Think about what could (will!!!) happen if you run two of these at the same time
Should be wrapped in a transaction.
And you don't need Max, either, Use Scope_Identity
You could run Select Scope_Identity() after the Insert statement. Then in your DAL Method return Convert.ToInt32(cmd.ExecuteScalar())
Change this:
return cmd.ExecuteNonQuery();
to
Int i = cmd.ExecuteScalar();
If you are only returning one integer from that procedure.
ExecuteNonQuery() isnt the method you want to be using here

passing multiple parameters to sql procedure as a single string variable

From front end(studio 2008) I am passing values to sql procedure as :
string a = "hello" + "098765" + "world" + "90.0909"
These are 4 different values that I've concatenated into a string a;
now i pass this string a to the sql procedure using c# sqlCommand object.
Now, how do I retrieve these 4 values in sql procedure as I've created the procedure as:
create procedure Proc_name (#concatenated_string varchar(100))
as
insert into table1 values(**how can i get those 4 values here**).
I used arrays but it didn't work.
If you want to pass an array into SQL Server to deal with "multirow" updates on one table, read this famous article(s).
If you want a generic stored proc to update any table, then don't as per other comments
The standard way to do this would be to use four parameters on the procedure:
create procedure Proc_name (#param1 varchar(100),
#param2 varchar(100),
#param3 varchar(100),
#param4 varchar(100))
as
insert into table1 values(#param1, #param2, #param3, #param4)
Then from your code (giving a c# example using ADO.NET)
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
SqlCommand command = new SqlCommand
("Proc_name", connection);
command.CommandType = CommandType.StoredProcedure;
// Add the input parameters and set the properties.
SqlParameter parameter1 = new SqlParameter();
parameter.ParameterName = "#Param1";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = param1;
SqlParameter parameter2 = new SqlParameter();
parameter.ParameterName = "#Param2";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = param2;
// Same for params 3 and 4...
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter1);
command.Parameters.Add(parameter2);
command.Parameters.Add(parameter3);
command.Parameters.Add(parameter4);
// Open the connection and execute the reader.
connection.Open();
SqlDataReader reader = command.ExecuteNonQuery();
reader.Close();
}
If you are using SQL Server 2005 then you might want to look at sending your data through to your stored procedure as an XML parameter. This link explains the process perfectly
Here's a sample section of how your code might look using .NET 3.5 and C#
// sample object
[Serializable]
internal class MyClass
{
internal string Property1 { get; set; }
internal string Property2 { get; set; }
internal int Property3 { get; set; }
internal string Property4 { get; set; }
}
// sample serialization
internal static string SerializeObject<T>(T objectGraph)
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
writerSettings.Indent = true;
using (XmlWriter xmlWriter = XmlWriter.Create(sb, writerSettings))
{
XmlSerializer xs = new XmlSerializer(typeof(T));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(String.Empty, String.Empty);
xs.Serialize(xmlWriter, objectGraph, ns);
}
return sb.ToString();
}
// sample stored procedure
Create PROCEDURE [dbo].[MyProc]
#myClassXML XML
AS
BEGIN
INSERT INTO [dbo].[MyTable]
(
P1,
P2,
P3,
P4
)
SELECT
Container.ContainerCol.value('Property1[1]', 'varchar(50)') AS P1,
Container.ContainerCol.value('Property2[1]', 'varchar(50)') AS P2,
Container.ContainerCol.value('Property3[1]', 'int') AS P3,
Container.ContainerCol.value('Property4[1]', 'varchar(50)') AS P4,
FROM #myClassXML.nodes('//MyClass') AS Container(ContainerCol)
END
I am assuming that you've read the advice of other answers here and are not creating a generic "Insert Anything" stored procedure as this is one of the worst things that you could do.
Note: This code was written in Notepad++ and thus hasn't been tested.
You could concatenate the 4 strings with a comma between and split it in the database back.
E.g.
declare #values as nvarchar(1000)
set #values = 'hello,098765,world,90.0909'
SELECT * FROM split(#values)
---------------- SPLIT FUNCTION --------------
CREATE FUNCTION [dbo].[split]
(
#csv nvarchar(max)
)
RETURNS
#entries TABLE
(
entry nvarchar(100)
)
AS
BEGIN
DECLARE #commaindex int
SELECT #commaindex = CHARINDEX(',', #csv)
IF #commaindex > 0
BEGIN
INSERT INTO #entries
-- insert left side
SELECT LTrim(RTrim(LEFT(#csv, #commaindex-1)))
-- pass right side recursively
UNION ALL
SELECT entry
FROM dbo.split(RIGHT(#csv, LEN(#csv) - #commaindex))
END
ELSE
INSERT INTO #entries
SELECT LTrim(RTrim(#csv))
RETURN
END
use several parameters instead of 1, e.g.:
CREATE PROCEDURE [dbo].[addUser]
#idRole int,
#userName varchar(255),
#password varchar(255)
AS
BEGIN
set nocount on
insert into userTbl ( idRole , userName , password )
VALUES ( #idRole , #userName , #password )
return scope_identity();
END
GO
If you really do just want to use one parameter, then maybe consider an XML parameter rather than a string.
public List<T> updateSiteDetails<T>(int SiteId, int CategoryId, string[] values)
{
int temp = values.Count();
int Counter = 0;
List<T> SiteDetails = null;
var parameterData = new string[temp];
var para = new string[temp];
foreach (string value in values)
{
Counter =Counter++;
parameterData[Counter] = "#,value"+Counter;
para[Counter] = string.Format(","+value);
}
//string ParameterDatas=string.Join(",",parameterData);
string parameterValue = string.Join(",",para);
using (SBDEntities db = new SBDEntities())
{
SiteDetails = db.Database.SqlQuery<T>("Sp_Update_Data #SiteId,#CategoryId" + string.Join(",", parameterData),string.Join(",",para)
//new Object[] { new SqlParameter("#SiteId", SiteId),
// new SqlParameter("#CategoryId",CategoryId)}
).ToList();
}
return SiteDetails;
}
in case you are using stored procedure with Entity framework

Categories