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
Related
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.
I am trying to start usign stored procedures. Well, I currently have a query that is just returning a single value that is a string. I can't seem to see what I am doing incorrectly here.
The sql is below:
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #ReturnVal Varchar(20)
-- Insert statements for procedure here
set #ReturnVal = (select a.AccBCPublicId from [MyTable Goes Here] a where a.AccId = #ACCId)
return #ReturnVal
END
using (SqlCommand sqlCommand = new SqlCommand("[dbo].[My Stored Procedure]", sqlConnection) { CommandType = CommandType.StoredProcedure })
{
//clean the starting 0's before sending. Originally had leading zeros
sqlCommand.Parameters.Add(new SqlParameter("#ACCId", strAccId.TrimStart(Convert.ToChar("0"))));
SqlParameter returnParam = new SqlParameter("#ReturnVal", SqlDbType.NVarChar, 20) {Direction = ParameterDirection.ReturnValue };
sqlCommand.Parameters.Add(returnParam);
sqlCommand.ExecuteNonQuery();
string bcAccount = (string)returnParam.Value;
}
I keep getting the following error. I do see why it is seeing as int value type.
Conversion failed when converting the varchar value 'bc:99988' to data type int.
A value passed with the RETURN T-SQL statement can only be an integer expression, you can't pass back a string. It seems that the simplest option is to use ExecuteScalar
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select a.AccBCPublicId from [MyTable Goes Here] a where a.AccId = #ACCId
And in your code use
using (SqlCommand sqlCommand = new SqlCommand(.....))
{
sqlCommand.Parameters.Add(.....)
object result = sqlCommand.ExecuteScalar();
if(result != null)
string bcAccount = result.ToString();
....
}
I want to get inserted row key when inserting records.Then I wrote this Sample SQL SP.
CREATE PROCEDURE Temp
AS
BEGIN
SET NOCOUNT ON
insert into Farmer_landDetails
(oth_mas_key,
fmr_key,
anim_typ_key,
anim_count,
land_type_key,
land_availability) OUTPUT INSERTED.oth_det_key values(1,1,1,1,1,1)
END
GO
How to get this OUT value with C# ?
The Output clause of your StoredProcedure returns a single row with a single value.
So the correct method to get its result is through the ExecuteScalar method of an SqlCommand
using(SqlConnection cnn = new SqlConnection(....))
using(SqlCommand cmd = new SqlCommand("Temp", cnn))
{
cnn.Open();
cmd.CommandType = CommandType.StoredProcedure;
int result = Convert.ToInt32(cmd.ExecuteScalar());
}
Notice that I have no idea what datatype is oth_det_key. I assume an integer hence the Convert.ToInt32() on the return value of ExecuteScalar
I've been trying to insert some data on a database and at the same time get the identifier.
The identifier type is a Guid.
I already tried some resolutions.
I was searching but I couldn't found any that worked with a Guid in C#.
The last one I tried was like this:
dbAccess db = new dbAccess();
SqlConnection con = db.openConnection();
Guid retVal = Guid.Empty;
try
{
SqlCommand cmd = new SqlCommand(#"insert into Comment(IdDiscussion,UserId,Description,DateTime)
values(#IdDiscussion,#UserId,#description,#dateTime);
set #ret=SCOPE_IDENTITY();", con);
cmd.Parameters.AddWithValue("#IdDiscussion", discussionId);
cmd.Parameters.AddWithValue("#UserId", userId);
cmd.Parameters.AddWithValue("#description", comment);
cmd.Parameters.AddWithValue("#dateTime", dateTime);
SqlParameter retParameter = new SqlParameter("#ret", SqlDbType.UniqueIdentifier);
retParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(retParameter);
cmd.ExecuteNonQuery();
retVal = (Guid)retParameter.Value;
}
catch (Exception e)
{
//doesn't really matter
}
db.closeConnection();
return retVal;
In this case I get the following error on executeNonQuery(): "Operand type clash: numeric is incompatible with uniqueidentifier".
Any suggestion that can help?
scope_identity() only returns the last (scoped) identity value - this value datatype has to be numeric.
So unfortunetly only fix that comes to my mind would be something like this:
declare #op table
(
ColGuid uniqueidentifier
)
insert into Comment(IdDiscussion,UserId,Description,DateTime)
output inserted.CommentId -- GUID column
into #op
values (#IdDiscussion,#UserId,#description,#dateTime)
select top 1 o.ColGuid
from #op o
and then in your code:
var guid = (Guid)cmd.ExecuteScalar();
One more mention: this solution should work in SQL Server 2005 and above
I tried to use SCOPE_IDENTITY() to retrieve Guid values, but not worked with me. You can try declare a SQL variable and generate a new guid with the command NEWID() and in the end do a SELECT command in this variable executing ExecuteScalar method on the command object.
DECLARE #Id UNIQUEIDENTIFIER; SET #Id = NEWID();
INSERT INTO [tablename] ([Id], [Field1], [Field2]) VALUES (#Id, #Field1, #Field2);
You must add your parameters on the command normally.
cmd.Parameters.AddWithValue("#Field1", "Field 1 Value");
cmd.Parameters.AddWithValue("#Field2", "Field 2 Value"));
So, execute and retrieve the value.
var obj = cmd.ExecuteScalar();
Guid guid = (Guid)obj;
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