Trying to use a SQL stored procedure in Windows Forms - c#

The following code is causing problem in my Windows Forms app:
SqlConnection cnnDB = new SqlConnection(<connection string>);
try
{
SqlCommand cmd = cnnDB.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_ProcName";
cmd.Parameters.AddWithValue("#int1", ComboBox1.SelectedValue);
cmd.Parameters.AddWithValue("#int2", ComboBox2.SelectedValue);
cmd.Parameters.AddWithValue("#int3", ComboBox3.SelectedValue);
cmd.Parameters.AddWithValue("#int4", ComboBox4.SelectedValue);
cmd.Parameters.AddWithValue("#varchar1", TextBox1.Text);
cmd.Parameters.AddWithValue("#varchar2", TextBox2.Text);
cmd.Parameters.AddWithValue("#varchar3", ComboBox5.SelectedValue);
cmd.Parameters.AddWithValue("#varchar4", stringVariable);
cnnDB.Open();
cmd.ExecuteNonQuery();
cnnDB.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
This is what happens when I execute it:
If stringVariable is either "Insert" or "Update", data from TextBox1 and TextBox2 isn't passed to procedure.
If stringVariable is "Delete", I get error “Procedure or function ‘sp_ProcName’ expects parameter ‘#varchar3’, which was not supplied”.
Is there something wrong with the code?
EDIT: As requested by #Steve and #MethodMan, below is the stored procedure in SQL Server.
ALTER PROCEDURE [dbo].[sp_ProcName]
(
#int1 int,
#int2 int,
#int3 int,
#int4 int,
#varchar1 varchar(7),
#varchar2 varchar(6),
#varchar3 nvarchar(10),
#varchar4 nvarchar(10) = ''
)
AS
BEGIN
SET NOCOUNT ON;
IF #varchar4 = 'Insert'
BEGIN
INSERT INTO Table1(int1,int2,int3,int4,varchar1,varchar2,varchar3)
VALUES(#int1,#int2,#int3,#int4,#varchar1,#varchar2,#varchar3)
END
IF #varchar4 = 'Update'
BEGIN
UPDATE Table1
SET int1=#int1, int2=#int2, int3=#int3, int4=#int4, varchar1=#varchar1, varchar2=#varchar2, varchar3=#varchar3
WHERE varchar1 = #varchar1
END
IF #varchar4 = 'Delete'
BEGIN
DELETE FROM Table1
WHERE varchar1 = #varchar1
END
Well, after a closer examination, I see that the Update part in stored procedure is "bad egg". I'll need to find some other way. Delete part too.
P.S. Sorry for long question.

You need to use DBNull.Value instead of null or assign default values to your stored procedure parameters that might be missing:
Method 1 :
CREATE PROCEDURE [dbo].[problemParam]
// Other parameters go here then
#varchar1 NVARCHAR(50) = null,
#varchar1 NVARCHAR(50) = null,
#varchar1 NVARCHAR(50) = null,
AS
BEGIN
-- Procedure Logic go here
END
Method 2:
object param1 = DBNull.Value;
object param2 = DBNull.Value;
object param3 = DBNull.Value;
if(!String.IsNullOrEmpty(TextBox1.Text))
param1 = TextBox1.Text;
if(!String.IsNullOrEmpty(TextBox2.Text))
param2 = TextBox2.Text;
if(ComboBox5.SelectedValue != null)
param3 = TextBox1.Text;
cmd.Parameters.AddWithValue("#varchar1", param1 );
cmd.Parameters.AddWithValue("#varchar2", param2 );
cmd.Parameters.AddWithValue("#varchar3", param3 );

Related

Conversion error when i call a stored procedure from SQL Server in C#

I have a stored procedure called lastID like this:
CREATE PROCEDURE lastID(#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #f VARCHAR(64);
SELECT TOP 1 #f = work_id
FROM workorder
WHERE (RIGHT(work_id,2)) = (RIGHT(Year(getDate()),2))
ORDER BY work_id DESC;
IF(#f IS NULL)
BEGIN
SET #f = 'No work orders';
SET #id = #f;
RETURN #id;
END
ELSE
BEGIN
SET #id = #f;
RETURN #id;
END
END
This stored procedure returns the last id from the table workorder, now I'm trying to execute this procedure in C#, this is the code:
private void lastWorkId()
{
String strConnString = "Server=.\\SQLEXPRESS;Database=recalls;Integrated Security=true";
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "lastID";
cmd.Parameters.Add("#id", SqlDbType.VarChar, 64).Direction = ParameterDirection.Output;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
String id = cmd.Parameters["#id"].Value.ToString();
lastid.Text = id.ToString(); //Putting the return value into a label
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
}
I don't know what are wrong with my code, because an exception is displayed, and this says
Conversion failed when converting the varchar value ' OT- 003-16 ' to data type int
I was wrong about my first answer, here is the updated answer:
Your stored procedure is setup with an OUTPUT parameter of type VARCHAR(64).
Within your proc you have a couple of RETURN #id; statements, which is actually returning a VARCHAR(64). You only need to set your OUTPUT variable within the stored procedure. The RETURN statement expects an integer expression. Here's the updated fixed sproc using OUTPUT appropriately:
ALTER PROCEDURE [dbo].[lastID](#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #f VARCHAR(64);
SELECT TOP 1 #f = work_id FROM workorder WHERE (RIGHT(work_id,2)) = (RIGHT(Year(getDate()),2)) ORDER BY work_id DESC;
IF(#f IS NULL)
BEGIN
SET #f = 'No work orders';
SET #id = #f;
END
ELSE
BEGIN
SET #id = #f;
END
END
Error is basically should get fixed by cast
((RIGHT(work_id,2)) as int)
But code can be further condensed and improved.
CREATE PROCEDURE lastID(#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1 #id = isnull(work_id , 'No work orders') FROM workorder WHERE cast ((RIGHT(work_id,2)) as int)= (RIGHT(Year(getDate()),2)) ORDER BY work_id DESC;
RETURN #id;
END

Updating SQL Server database with values from textboxes using stored procedure

We have an aspx page which is a has a number of text boxes. We want to take the data entered into these textboxes and update our SQL Server database with them. However if any of the textboxes are left blank then we would like the data to be left as it is.
We have written the following stored procedure to carry out the update:
ALTER PROCEDURE pr_updateBooking
(
#BookingRef INT,
#BoatID INT,
#LeadPassenger INT,
#StartDate Date,
#Duration INT,
#Pets INT,
#Children INT,
#Passengers INT,
#SpecialRequests VARCHAR(255),
#BalanceOutstanding NUMERIC(12, 2),
#Comments VARCHAR(50)
)
AS
DECLARE #error INT
UPDATE BookingView
SET Balance_Outstanding = #BalanceOutstanding,
Comments = #Comments
WHERE Booking_Ref = #BookingRef
UPDATE vBoat_Booking
SET BoatID = #BoatID, Lead_PassengerID = #LeadPassenger,
Start_Date = #StartDate, Duration_In_hours = #Duration,
Number_of_pets = #Pets, Number_of_children = #Children,
Number_of_passengers = #Passengers
WHERE Booking_Ref = #BookingRef
SET #error = ##error
IF #error <> 0
RETURN 99
ELSE
RETURN 0
Here is the C# code which will be run when the submit button is clicked on our aspx page
protected void buttonClicked(object sender, EventArgs e)
{
string CS = ConfigurationManager.ConnectionStrings["G4StowawaysConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(CS);
conn.Open();
SqlCommand cmd2 = new SqlCommand("pr_updateBooking", conn);
cmd2.CommandType = CommandType.StoredProcedure;
// add our parameters to our command object
cmd2.Parameters.Add("#BookingRef", SqlDbType.Int).Value = BookingRef.Text;
cmd2.Parameters.Add("#BoatID", SqlDbType.Int).Value = BoatID.Text;
cmd2.Parameters.Add("#LeadPassenger", SqlDbType.Int).Value = LeadPassenger.Text;
cmd2.Parameters.Add("#StartDate", SqlDbType.Date).Value = StartDate.Text;
cmd2.Parameters.Add("#Duration", SqlDbType.Money).Value = Duration.Text;
cmd2.Parameters.Add("#Pets", SqlDbType.Int).Value = Pets.Text;
cmd2.Parameters.Add("#Children", SqlDbType.Int).Value = Children.Text;
cmd2.Parameters.Add("#Passengers", SqlDbType.Int).Value = Passengers.Text;
cmd2.Parameters.Add("#SpecialRequests", SqlDbType.VarChar, 255).Value = SpecialRequests.Text;
cmd2.Parameters.Add("#BalanceOutstanding", SqlDbType.Int).Value = BalanceOutstanding.Text;
cmd2.Parameters.Add("#Comments", SqlDbType.VarChar, 50).Value = Comments.Text;
try
{
if (cmd2.Connection.State == ConnectionState.Closed)
{
cmd2.Connection.Open();
}
cmd2.ExecuteNonQuery();
}
catch (Exception)
{
}
finally
{
cmd2.Connection.Close();
}
}
When we run the page there is no error message however the data is not appearing in the database!?
There are several issues in your application.
1. As noted in comments, use return value from int result = cmd.ExecuteNonQuery() (0 or 99). In fact it is not enough.
2. Check your table schemas to see whether or not fields of interest allow null.
3. In your stored procedure use transaction.
...
AS
--DECLARE #error INT --no need
begin transaction
begin try
UPDATE BookingView
SET Balance_Outstanding = #BalanceOutstanding, Comments = #Comments
WHERE Booking_Ref = #BookingRef
UPDATE vBoat_Booking
SET BoatID = #BoatID, Lead_PassengerID = #LeadPassenger, Start_Date = #StartDate, Duration_In_hours = #Duration, Number_of_pets = #Pets,
Number_of_children = #Children, Number_of_passengers = #Passengers
WHERE Booking_Ref = #BookingRef
commit
end try
begin catch
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
rollback
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
)
end catch
--SET #error = ##error
--IF #error <> 0 RETURN 99
--ELSE RETURN 0
In C# use catch part to see what happened.
The stored procedure will not accept nulls in the parameter values, so you have somewhat of a check in place - maybe. You really need to put some code in the Catch {} block to see if the procedure is returning an error.
I don't know WHERE you want to prevent the update. The problem, as presented, should be solved in the UI. If any of the entries are empty, then don't allow a submit. Simple.
If you want the procedure to avoid performing an update, then you should set all the parameters to allow nulls. Then check for any null values before allowing the update. You could throw a user defined error or 99 (as designed). This approach would also require that you only set parameter values when the textboxes are not empty.

How to read Scope Identity in C# from executed Stored Procedure

I want to read Scope_Identity via output variable '#RoleID' from where I am assigning value of scope identity.
C#:
private static long createNewRoleInsert(ADB.Model.RolesModel roleModelObj, MSSQL sql)
{
bool killConnection = Utils.getConnection(ref sql);
long returnValue = 0;
try
{
sql.SetSProc("[dbo].[p_Role_dfn_createNew]");
sql.AddParam("#Title", roleModelObj.Title);
sql.AddParam("#Description", roleModelObj.Description);
sql.AddParam("#CreatedDate", roleModelObj.CreatedDate);
var RoleID = sql.ExecuteNonQuery();
if(RoleID!=0 && RoleID>0)
{
returnValue = RoleID;
}
}
finally
{
if (killConnection)
sql.Dispose();
}
return returnValue;
}
Stored procedure:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[p_Role_dfn_createNew]
#Title nvarchar(250),
#Description nvarchar(MAX) = NULL,
#CreatedDate DateTime,
#RoleID bigInt OUTPUT
AS
SET NOCOUNT ON;
SET XACT_ABORT ON
DECLARE #l_object AS SYSNAME = OBJECT_NAME(##PROCID),
#l_error_msg AS NVARCHAR(2000)
BEGIN TRY
BEGIN TRAN
INSERT INTO [adb_TestDb].[dbo].[Role] ([Title], [Description], [CreatedDate])
VALUES (#Title, #Description, #CreatedDate)
COMMIT TRAN
SET #RoleID = SCOPE_IDENTITY();
RETURN #RoleID
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
The ExecuteNonQuery method doesn't return the return value from the procedure, it returns the number of rows affected.
To get the return value you would add a parameter with ParameterDirection.ReturnValue, however that won't safely get you the value in #RoleID as the return value from a procedure can't be a bigint, it's always an int.
As you already have #RoleID as an output parameter you should add parameter to the command to get the value. Example:
SqlParameter roleIdParam = new SqlParameter("#RoleID", SqlDbType.BigInt);
roleIdParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(roleIdParam);
// execute command
long roleId = (long)roleIdParam.Value;
You need to add an output parameter in C# to get the value of #RoleID from the stored procedure. Here's an example of that:
using System.Data.SqlClient;
using (SqlConnection conn = new SqlConnection("connectionString"))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.p_Role_dfn_createNew";
// add other parameters...
cmd.Parameters.Add(new SqlParameter("#RoleID", SqlDbType.BigInt))
.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
returnValue = (long)cmd.Parameters["#RoleID"].Value;
}
Change the
RETURN #RoleID
to
SELECT #RoleID
or add the output parameter as explained in other answers

returning int value from stored procedure and check it in asp.net code to validate login form

What is the true sequence to make this code run as I tried many time but I don't get a valid result
// the code of SQL stored procedure
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[login_proc] #username Varchar =50, #password varchar=50
as
Declare #user_name varchar , #pass_word varchar, #result varchar
Set #user_name = #username
Set #pass_word = #password
if EXISTS (select username , password from data where username= #user_name)
set #result= 1
else
set #result=0
return #result
and asp.net code is
SqlConnection conn = new SqlConnection ("Data Source=ANAGUIB-LAPNEW\\SQLEXPRESS;Initial Catalog=account;Integrated Security=True");
SqlCommand cmd = new SqlCommand("login_proc",conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter paramReturnValue = new SqlParameter();
paramReturnValue.ParameterName = "#result";
paramReturnValue.SqlDbType = SqlDbType.Int;
cmd.Parameters.Add(paramReturnValue);
cmd.Parameters["#result"].Direction = ParameterDirection.Output;
conn.Open();
cmd.Parameters.AddWithValue("#username", TextBox1.Text);
cmd.Parameters.AddWithValue("#password", TextBox2.Text);
cmd.ExecuteScalar();
string retunvalue = (string)cmd.Parameters["#result"].Value;
if (retunvalue == "1")
{
Response.Redirect("hello.aspx");
}
else
{
Response.Write("error");
}
conn.Close();
You're executing .ExecuteScalar() so you're expecting back a result set with a single row, single column from the stored procedure - but you're not selecting anything at the end of your stored proc!
You need to change your last line in the stored proc from
return #result
to
SELECT #result
and then it should work.
Add another parameter for the return value
ALTER PROC [dbo].[login_proc]
#username Varchar = 50,
#password Varchar = 50,
#result int OUTPUT
Examples can be viewd here.
Did you try this one;
Use the
return #result
and in c#
int resultID = Convert.ToInt32(cmd.ExecuteScalar());
Also remove next line
cmd.Parameters[""].value;
I'm unable to login any suggestions, both in case of stored procedure and codebehind can anyone provide solution to this,,,plz,,,

Ado.net ExecuteScalar() returning null

I am executing a stored procedure in c# (through vs2008) using ado.net with an ExecuteScalar command. The stored proc returns the pkey of the new record entered, but ExecuteScalar is returning null. I look in the database and a record has indeed been added. I could use an output parameter to get the value, but then I won't know why this didn't work.
When I execute the sp in ssms, the pkey is returned.
What am I doing wrong?
Here is the C# code:
public int SaveNewPerson(EPerson ePerson)
{
int newPersonPkey;
SqlConnection cn = new SqlConnection(cnn.PersonData);
using (cn)
{
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "People.dbo.AddNewPerson";
cmd.Parameters.Add("#LastName", SqlDbType.VarChar, 150).Value = ePerson.LastName;
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 150).Value = ePerson.FirstName;
cn.Open();
object result = cmd.ExecuteScalar();
newPersonPkey = int.Parse(result.ToString());
cn.Close();
}
catch (Exception e)
{
// call error method
throw new Exception(e.Message + " save new Person error ");
}
}
return newPersonPkey;
}
And this is the sp:
PROCEDURE [dbo].[AddNewPerson]
#FirstName varchar(50)
,#LastName varchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [People].[dbo].[Persons]
(
[FirstName]
,[LastName]
)
VALUES
(
#FirstName
,#LastName
)
declare #persons_PKey int
set #persons_PKey = ##IDENTITY
return #persons_PKey
end
The ExecuteScalar method returns the first field of the first record of the result, but as your query doesn't produce a result, it will return null.
You can either select the value instead of returning it from the stored procedure, or add a parameter with the direction set to ParameterDirection.ReturnValue to catch what the stored procedure returns.
Try changing the Stored Procedure to use a Select Statement to return the identity instead of using a return like this:
SELECT CAST(scope_identity() AS int)
Thus changing your procedure to:
PROCEDURE [dbo].[AddNewPerson]
#FirstName varchar(50)
,#LastName varchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [People].[dbo].[Persons]
(
[FirstName]
,[LastName]
)
VALUES
(
#FirstName
,#LastName
)
SELECT CAST(scope_identity() AS int)
end
From the documentation of the ExecuteScalar() on MSDN it says that it will return the first column of the first row in the result set or null otherwise if the result set is empty.

Categories