Updating SQL Server database with values from textboxes using stored procedure - c#

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.

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

Getting the output parameter value as DBNULL when using C# transaction

Stored procedure, inserting to the table, which has an identity column as ID
CREATE PROCEDURE InsertValue
#Value varchar(7),
#NewId int = 0 OUTPUT
AS
BEGIN
IF(NOT EXISTS(SELECT 1 FROM [Table1] WHERE Detail = #Value))
BEGIN
INSERT into [Table1] (Detail)
VALUES (#Value)
SET #NewId = SCOPE_IDENTITY();
END
END
C# code:
int newId=0;
SqlTransaction SqlTrans = null;
SqlConnection con = new SqlConnection("connection string");
con.Open();
cmd = new SqlCommand("InsertValue", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#Value", "123"));
SqlParameter parId= new SqlParameter("#NewId",DbType.Int32);
parId.Value= 0;
parId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(parId);
SqlTrans = con.BeginTransaction();
cmd.Transaction = SqlTrans;
try
{
cmd.ExecuteNonQuery();
// parId.Value is DBNULL
SqlTrans.Commit();
newId = Convert.ToInt32(parId.Value);
// Exception : This SqlTransaction has completed; it is no longer usable
}
catch (Exception e)
{
throw;
}
So can anyone help me with this? I want the transaction to be there in C# code, but need the value from out parameter.
If I access the value before committing the transaction, it is DBNull and if access after committing, getting exception while casting(the value is still DBNull)
This SqlTransaction has completed; it is no longer usable.
Take a look at the answers to these existing questions for This SqlTransaction has completed; it is no longer usable. Perhaps your stored procedure already commits the transaction, or the SQL Server is killing the transaction for some reason?
"This SqlTransaction has completed; it is no longer usable."... configuration error?
SqlTransaction has completed
Thanks everyone for the support and help.
Actually the problem was with the output parameter's default value.
I forgot to specify the condition in the question(now i have added it), which was preventing the value of the output parameter to be set each time.
As i was passing the output parameter value as 0 each time, so it was supposed to be 0 when it is not getting set in the SP.
But, the output parameter was getting as DBNull in case it is not set in the procedure.
So i changed the procedure to set the value of the parameter each time, irrespective of the condition.
CREATE PROCEDURE InsertValue
#Value varchar(7),
#NewId int = 0 OUTPUT
AS
BEGIN
SET #NewId = 0; -- Added to set it to 0
IF(NOT EXISTS(SELECT 1 FROM [Table1] WHERE Detail = #Value))
BEGIN
INSERT into [Table1] (Detail)
VALUES (#Value)
SET #NewId = SCOPE_IDENTITY();
END
END

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

data insert using input output stored procedure

I am creating a web application using ASP.net C#. I have a booking form and I need to insert data into a table using a Stored Procedure. The table has several columns, out of which second column is a computed column. The Stored Procedure is set up to insert the data and fetch the value from the second column after insert. Below is the code for Stored Procedure:
Create Procedure sp_InsertCashPooja
#FirstName varchar(100),
#LastName varchar(100),
#TelNo bigint,
#Star char(50),
#Rasi char(50),
#Gothram char(50),
#PDMID int,
#PayMode bit,
#PujaName char(50),
#DonateAmt decimal(19,2),
#RcptNo varchar(25) output
as
Begin
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION
if #PujaName != 'DONATION'
Begin
INSERT INTO PoojaDetails (FirstName, LastName, TelNo, Star, Rasi, Gothram, PoojaDietyMasterID, PayMode) values (#FirstName,#LastName,#TelNo,#Star,#Rasi,#Gothram,#PDMID,#PayMode)
End
if #PujaName = 'DONATION'
Begin
DECLARE #isDonate int = 0;
INSERT INTO PoojaDetails (FirstName, LastName, TelNo, Star, Rasi, Gothram, PoojaDietyMasterID, PayMode, isDonate, DonateAmount) values (#FirstName,#LastName,#TelNo,#Star,#Rasi,#Gothram,#PDMID,#PayMode, #isDonate, #DonateAmt)
End
Select #RcptNo = max(ReceiptNo) from PoojaDetails
Return #RcptNo
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF (##TRANCOUNT > 0)
ROLLBACK TRANSACTION
END CATCH
SET NOCOUNT OFF;
End
I would like to insert data on the click of a button: I was able to figure out the below code....
protected void btnSave_Click(object sender, EventArgs e)
{
frmFirstName = txtFirstName.Text.Trim().ToUpper();
frmLastName = txtLastName.Text.Trim().ToUpper();
frmPhoneNo = Convert.ToInt32(txtPhoneNo.Text.Trim());
frmNakshatra = Convert.ToString(cmbNakshatra.SelectedItem).Trim();
frmRasi = Convert.ToString(cmbRasi.SelectedItem).Trim();
frmGothram = Convert.ToString(cmbGothram.SelectedItem).Trim();
frmPujaName = Convert.ToString(cmbPujaName.SelectedItem).Trim();
using (SqlConnection connection = new SqlConnection())
{
if (frmPayMode == "Cash")
{
if (frmPujaName == "DONATION")
{
SqlDataAdapter CashAdapter = new SqlDataAdapter();
CashAdapter.InsertCommand = new SqlCommand("sp_InsertCashPooja", connection);
CashAdapter.InsertCommand.CommandType = CommandType.StoredProcedure;
Please help.... I want to capture the returning RcptNo and later intend to call another ASPX page and pass the value using a Query String.
Thanks
Use simple SqlCommand for calling your SP
connection.Open();
var cmd = new SqlCommand("sp_InsertCashPooja", connection);
cmd.Parameters.AddWithValue("FirstName", frmFirstName);
// Add all the others parameters in same way
var id = (int)cmd.ExecuteScalar();
connection.Close();
Change the return variable to:
Select #RcptNo = SCOPE_IDENTITY()
It will return the identity number created for the inserted record within this procedure.
use sql parameter..
connection = ConfigurationManager.AppSettings["mycon"];
SqlParameter[] para = new SqlParameter[2];
para[0] = new SqlParameter("#stored procedure column name", string name);
para[1] = new SqlParameter("#stored procedure column name", string name);

Error converting data type varchar to int

This is my stored procedure code
ALTER procedure [Proc_Add_User]
(#UserId varchar(20),
#UserName varchar(100),
#Page_Name varchar(20),
#AccessIndicator int,
#CreatedBy varchar(50),
#returnStatus varchar(50) output)
as
DECLARE #intErrorCode INT
DECLARE #Page_Indicator INT
begin
BEGIN TRAN
Set #Page_Indicator = (select Page_Indicator from Pages where Page_Name=#Page_Name);
if (select count(*) from Users where UserId=#UserId and UserName=#UserName) > 0 begin
if (select count(*) from User_Credentials where Page_Indicator=#Page_Indicator and
UserId=#UserId ) > 0
set #returnStatus='User already has access'
else
insert into User_Credentials(UserId,Page_Indicator,Access_Indicator,CreatedBy)
values (#UserId,#Page_Indicator,#AccessIndicator,#CreatedBy)
SELECT #intErrorCode = ##ERROR
IF (#intErrorCode <> 0) GOTO PROBLEM
end
else begin
insert into Users(UserId,UserName,CreatedBy)
values(#UserId,#UserName,#CreatedBy)
SELECT #intErrorCode = ##ERROR
IF (#intErrorCode <> 0) GOTO PROBLEM
insert into User_Credentials(UserId,Page_Indicator,Access_Indicator,CreatedBy)
values (#UserId,#Page_Indicator,#AccessIndicator,#CreatedBy)
SELECT #intErrorCode = ##ERROR
IF (#intErrorCode <> 0) GOTO PROBLEM
end
COMMIT TRAN
if(#returnStatus is null)
set #returnStatus='Success';
PROBLEM:
IF (#intErrorCode <> 0) BEGIN
set #returnStatus= 'Unexpected error occurred!'
ROLLBACK TRAN
end
end
And I am calling this from the code pasted below:
Con.Open();
cmd = new OleDbCommand();
cmd.Connection = Con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Proc_Add_User";
cmd.Parameters.Clear();
cmd.Parameters.Add("#UserId", SqlDbType.VarChar).Value = userLanId;
cmd.Parameters.Add("#UserName", SqlDbType.VarChar).Value = userName;
cmd.Parameters.Add("#Page_Name", SqlDbType.VarChar).Value = pageName;
cmd.Parameters.Add("#AccessIndicator", SqlDbType.Int).Value = accessIndicator;
cmd.Parameters.Add("#CreatedBy", SqlDbType.VarChar).Value = createdBy;
OleDbParameter output = new OleDbParameter("#returnStatus", SqlDbType.VarChar);
output.Direction = ParameterDirection.Output;
cmd.Parameters.Add(output);
int result = cmd.ExecuteNonQuery();
I am getting the error mentioned at the ExecuteNonQuery statement. What's confusing to me is I am able to execute the stored procedure in SSMS but not from my application (front-end). I provided the same values too yet it fails from my app.
I double checked to make sure the order of parameters passed match and are of same data type but still it throws this error. I can paste my stored proc code here if wanted so let me know..Thanks in advance!
EDIT
OOPS! I just realized that all the inserts are all happening and getting committed fine in the database. It's just this error is getting caught inside catch block in my app. Any ideas?
I can not ignore it because based on the return value of ExecuteNonQuery(), I have some statements and also it's not going through the code present after ExecuteNonQuery().
This is most likely because you are using SqlDbType with OleDbParameters:
OleDbParameter output = new OleDbParameter("#returnStatus", SqlDbType.VarChar);
This causes .NET to use the OleDbParameter(String, Object) constructor, setting the value of the parameter to SqlDbType.VarChar which it assumes is an int.
You should use this instead:
OleDbParameter output = new OleDbParameter("#returnStatus", OleDbType.VarChar);
And change your calls to cmd.Parameters.Add to use OleDbType as well.
Alternatively, you could use System.Data.SqlClient instead of OleDb

Categories