SQL Transaction with Parameters - c#

I am using a SQL Transaction statement to execute a stored procedure. Traditionally, I would use command parameters to insert different variables into the command.
When I tried to use the same method with a Transaction, the procedure would not insert into the database, although the transaction would work without an error.
Here is how I am trying to do it:
SqlConnection db = DataConn.SqlConnection();
db.Open();
SqlTransaction transaction = db.BeginTransaction();
try
{
const string strSql = "procSiteAddMember #uID, #userName, #password, #nickname, #email, #siteAddress";
var sqlComm = new SqlCommand(strSql, db, transaction) {CommandType = CommandType.Text};
sqlComm.Parameters.Add(new SqlParameter("#uID", SqlDbType.VarChar, 255)).Value = uID;
sqlComm.Parameters.Add(new SqlParameter("#userName", SqlDbType.VarChar, 20)).Value =
txtRegisterUsername.Text.Trim();
sqlComm.Parameters.Add(new SqlParameter("#password", SqlDbType.VarChar, 20)).Value =
txtRegisterPassword.Text;
sqlComm.Parameters.Add(new SqlParameter("#nickname", SqlDbType.VarChar, 20)).Value =
txtRegisterNickname.Text.Trim();
sqlComm.Parameters.Add(new SqlParameter("#email", SqlDbType.VarChar, 20)).Value = txtRegisterEmail.Text.Trim();
sqlComm.Parameters.Add(new SqlParameter("#siteAddress", SqlDbType.VarChar, 20)).Value = lblNickname.Text.Trim();
//sqlComm.ExecuteNonQuery();
//DataConn.Disconnect();
transaction.Commit();
Response.Redirect("~/Member/" + txtRegisterNickname.Text);
}
catch (Exception ent)
{
Response.Write("Error: " + ent.Message);
}
I saw This post - But it seems pretty long winded with a lot of variables.

You already solved this but since no one answered I'll do it for future reference.
You still need to execute the query so uncommment your line sqlComm.ExecuteNonQuery();
Also don't forget to add transaction.Rollback(); in your catch block, which you have to put inside another try-catch block in case the Rollback throws an exception.
Example:
try
{
...
transaction.Commit();
}
catch (Exception ex)
{
try
{
...
transaction.Rollback();
}
catch (Exception ex2)
{
...
}
}
For more information visit: https://msdn.microsoft.com/en-us/library/86773566(v=vs.110).aspx

Related

C# can't insert into Data Source

Here is my code:
try
{
SqlCommand cmd2 = new SqlCommand(#"INSERT INTO Clienti (parola,nume,prenume,adresa,email,kcal_zilnice) VALUES (#Parola,#Nume,#Prenume,#Adresa,#Email,2000)", conn);
cmd2.Prepare();
cmd2.Parameters.AddWithValue("#Parola", passBox.Text);
cmd2.Parameters.Add("#Nume", SqlDbType.VarChar, 50).Value = nameBox.Text;
cmd2.Parameters.Add("#Prenume", SqlDbType.VarChar, 50).Value = pnameBox.Text;
cmd2.Parameters.Add("#Adresa", SqlDbType.VarChar, 100).Value = adressBox.Text;
cmd2.Parameters.Add("#Email", SqlDbType.VarChar, 100).Value = emailBox.Text;
cmd2.ExecuteNonQuery();
}
catch (SqlException exception)
{
MessageBox.Show("Failed! " + exception.Message);
}
MessageBox.Show("User Created!");
I don't know what am I doing wrong here. I even tried to replace #Parola with 'abc' but it does not work. I don't get any error message. Every time I get "User Created", but when I look into the DB I get all the fields NULL(no records where created).
So, for anyone that has the same problem Prepare() solved it.
Use Add() for params and specify The SqlDbType. Prepare() will not work with AddWithValue().
At the end do Prepare() and then ExecuteNonQuery().

Local Database Insert query does nothing

I am trying to insert a row into the database. Below is my query:
using (SqlConnection conn = new SqlConnection("Data Source = (LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Traindata.mdf;Integrated Security=True"))
{
string query = "INSERT INTO dbo.Station (Naam, X, Y, Sporen) VALUES (#naam, #x, #y, #sporen)";
using (SqlCommand command = new SqlCommand(query, conn))
{
command.Parameters.AddWithValue("#naam", insert[1]);
command.Parameters.AddWithValue("#x", insert[2]);
command.Parameters.AddWithValue("#y", insert[3]);
command.Parameters.AddWithValue("#sporen", insert[4]);
conn.Open();
try
{
command.ExecuteNonQuery();
}
catch (SqlException exc)
{
Console.WriteLine("Error to save on database");
Console.WriteLine(exc.Message);
}
conn.Close();
}
}
When I run it nothing happens (Also no SQL errors). What am I doing wrong? I am sorry if this is a stupid question, I am merely a beginner.
This should work (I have tested this with a select query that does work).
Have you tried storing the query on a stored procedure and calling it from C#? ... Thats actually easier than making the query via hard code inside the C# code ... Just create a stored procedure that does whatever you want it to do, then call it from C# and add the parameters. It should look something like this:
SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Your_Conection_String_s_Name"].ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "dbo.Your_Stored_Procedure";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Input_Param_1", SqlDbType.VarChar, 18).Value = "C#_Parameter1";
cmd.Parameters.Add("#Input_Param_2", SqlDbType.VarChar, 45).Value = "C#Parameter_2";
cmd.Parameters.Add("#Input_Param_3", SqlDbType.VarChar, 45).Value = "C#Parameter_3";
cmd.Parameters.Add("#Input_Param_4", SqlDbType.Text).Value = "C#Parameter_4";
cmd.Parameters.Add("#Input_Param_5", SqlDbType.VarChar, 45).Value = "C#Parameter_5";
cmd.Parameters.Add("#Output_Parameter_1", SqlDbType.VarChar, 250).Direction = ParameterDirection.Output;
cmd.Parameters.Add("#Output_Parameter_2", SqlDbType.DateTime).Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
"C#Output_Parameter_1" = "" + cmd.Parameters["#Output_Parameter_1"].Value;
"C#Output_Parameter_2" = "" + cmd.Parameters["#Output_Parameter_2"].Value;
Hope it helps.
My guess is that you have a type mismatch
If x, y are not int then substitute in the correct type
using (SqlConnection conn = new SqlConnection("Data Source = (LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Traindata.mdf;Integrated Security=True"))
{
using (SqlCommand command = SqlCommand.CreateCommand())
{
try
{
conn.Open();
command.Query = "select count(*) from dbo.Station";
Int32 rowsRet = (Int32)command.ExecuteScalar();
Console.WriteLine(rowsRet.ToString());
command.Query = "INSERT INTO dbo.Station (Naam, X, Y, Sporen) VALUES (#naam, #x, #y, #sporen)";
command.Parameters.AddWithValue("#naam", insert[1]);
command.Parameters.Add("#x", SqlDbType.Int);
command.Parameters["#x"].Value = Int32.Parse(insert[2]);
command.Parameters.Add("#y", SqlDbType.Int);
command.Parameters["#y"].Value = Int32.Parse(insert[3]);
command.Parameters.AddWithValue("#sporen", insert[4]);
rowsRet = command.ExecuteNonQuery();
Console.WriteLine(rowsRet.ToString());
command.Query = "select count(*) from dbo.Station";
Int32 rowsRet = (Int32)command.ExecuteScalar();
Console.WriteLine(rowsRet.ToString());
}
catch (SqlException exc)
{
Console.WriteLine("Error to save on database");
Console.WriteLine(exc.Message);
}
finally
{
conn.Close();
}
// op claims the insert is gone the next time the programs is run
try
{
conn.Open();
command.Query = "select count(*) from dbo.Station";
Int32 rowsRet = (Int32)command.ExecuteScalar();
Console.WriteLine(rowsRet.ToString());
}
catch (SqlException exc)
{
Console.WriteLine("Error to save on database");
Console.WriteLine(exc.Message);
}
finally
{
conn.Close();
}
}
}

How To Catch Sql Server Error from Ado.net

I have the following code which calls a stored procedure. I want to be able to trap any error that occurs during the running of the stored procedure.
try {
using (var connection = GetConnection()) {
using (SqlCommand cmd = connection.CreateCommand()) {
connection.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "VerifyInitialization";
cmd.Parameters.Add(new SqlParameter("#userId", user.Id));
cmd.Parameters.Add(new SqlParameter("#domainId", user.DomainId));
cmd.ExecuteNonQueryAsync();
}
}
}
catch (Exception ex) {
throw new LoginException(LoginExceptionType.Other, ex.Message);
}
This is the stored procedure, which basically just calls other stored procedures.
ALTER PROCEDURE [dbo].[VerifyInitialization]
-- Add the parameters for the stored procedure here
#userId int,
#domainId int
AS
BEGIN
Begin Try
SET NOCOUNT ON;
Exec VerifyInitializationOfDefaultLocalizationItems
Exec VerifyInitializationOfLayoutLists #domainId
Exec VerifyInitializationOfLayoutListItems #domainId
Exec VerifyInitializationOfLocalizationItems #domainId
Exec VerifyInitializationOfLookupLists #domainId
Exec VerifyInitializationOfLookupListItems #domainId
End try
Begin Catch
-- Raise an error with the details of the exception
DECLARE
#ErrMsg nvarchar(4000) = Error_message(),
#ErrSeverity int = ERROR_SEVERITY();
RAISERROR(#ErrMsg, #ErrSeverity, 1)
End Catch
End
What do I need to do to catch an error in the Stored Proc that will be returned back to C#? Say for example a field name is renamed which prevents one of the stored procs from running. I don't want it to fail silently.
Greg
Using ExecuteNonQueryAsync() in your case, isn't as good as using ExecuteNonQuery().
try {
using (var connection = GetConnection()) {
using (SqlCommand cmd = connection.CreateCommand()) {
connection.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "VerifyInitialization";
cmd.Parameters.Add(new SqlParameter("#userId", user.Id));
cmd.Parameters.Add(new SqlParameter("#domainId", user.DomainId));
//cmd.ExecuteNonQueryAsync(); - This line should be .ExecuteNonQuery()
cmd.ExecuteNonQueryAsync();
}
}
}
catch (Exception ex) {
throw new LoginException(LoginExceptionType.Other, ex.Message);
}
Another thing you may want to consider is catching a more specific SqlException as opposed to the more general Exception, like this:
catch (SqlException exc) {
throw new SqlException(/* Handle your exception messaging here. */);
}
catch (Exception ex) {
throw new LoginException(LoginExceptionType.Other, ex.Message);
}
EDIT: I posted this answer not realizing that #usr had already answered it in the comments above. I will delete if you like.

C# Database adding to a table

I am using a .mdf database in Visual Studio 2010. When I add information to my table I get error. I don't get any problem when I add the first four rows. But when I add the fifth row I get error.
Here is the error:
SqlException was unhandled
What can the problem be?
dataAccess.AddQuestion("Category1", "Question1?", "1");
dataAccess.AddQuestion("Category2", "Question2?", "2");
dataAccess.AddQuestion("Category3", "Question3?", "3");
dataAccess.AddQuestion("Category4", "Question4?", "4");
dataAccess.AddQuestion("Category5", "Question5?", "5");
I get the error when I add the question number five.
Here is the method for how I add the information to the table in the database.
public void AddQuestion(string title, string question, string answer)
{
sqlConnection = new SqlConnection(connectionString);
sqlCommand = new SqlCommand("INSERT INTO QuestionTable VALUES(#Title, #Question, #Answer)", sqlConnection);
try
{
sqlConnection.Open();
sqlCommand.Parameters.Add(new SqlParameter("#Title", title));
sqlCommand.Parameters.Add(new SqlParameter("#Question", question));
sqlCommand.Parameters.Add(new SqlParameter("#Answer", answer));
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
}
catch (Exception ex)
{
throw(ex);
}
}
Is there a reason not to use method scoped variables for the SQL objects? Try to use this:
public void AddQuestion(string title, string question, string answer)
{
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
using (SqlCommand sqlCommand = new SqlCommand("INSERT INTO QuestionTable VALUES(#Title, #Question, #Answer)", sqlConnection))
{
try
{
sqlConnection.Open();
sqlCommand.Parameters.Add(new SqlParameter("#Title", title));
sqlCommand.Parameters.Add(new SqlParameter("#Question", question));
sqlCommand.Parameters.Add(new SqlParameter("#Answer", answer));
sqlCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
throw;
}
}
}
If you consider moving to SQL Server 2008 or newer, you might also look into Table-Valued Parameters.
Why don't you use multiple insert statement to insert multiple rows at once as their is always a limit on the no of connection to database per app pool so either you must not close the connection or use multiple insert at once
try the following code maybe you need to lock()
private static readonly object Locker = new object();
public void AddQuestion(string title, string question, string answer)
{
lock (Locker)
{
try
{
sqlConnection = new SqlConnection("");
sqlCommand = new SqlCommand("INSERT INTO QuestionTable VALUES(#Title, #Question, #Answer)", sqlConnection);
sqlConnection.Open();
sqlCommand.Parameters.Add(new SqlParameter("#Title", title));
sqlCommand.Parameters.Add(new SqlParameter("#Question", question));
sqlCommand.Parameters.Add(new SqlParameter("#Answer", answer));
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
}
catch (Exception ex)
{
MessageBox.Show("That is the Error:" ex.ToString()); // post this Text if it doesn't work
throw (ex);
}
}
}
I have found the problem (error)! In the database I was using nvarchar(50), but I hade one string which was 52 characters. I got the error because of that.

Should I call Parameters.Clear when reusing a SqlCommand with a transation?

I'm coding a transaction manually in ADO.NET. The example I'm working from reuses the SqlCommand which seem like a fine idea.
However, I have added parameters to my command.
My question is: in the following code, is command.Parameters.Clear() correct? Or am I doing it wrong?
using (var connection = new SqlConnection(EomAppCommon.EomAppSettings.ConnStr))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
SqlCommand command = connection.CreateCommand();
command.Transaction = transaction;
try
{
foreach (var itemIDs in this.SelectedItemIds)
{
command.CommandText = "UPDATE Item SET payment_method_id = #batchID WHERE id in (#itemIDs)";
// IS THE FOLLOWING CORRECT?
command.Parameters.Clear();
command.Parameters.Add(new SqlParameter("#batchID", batchID));
command.Parameters.Add(new SqlParameter("#itemIDs", itemIDs));
command.ExecuteNonQuery();
}
transaction.Commit();
}
catch (Exception ex)
{
MessageBox.Show("Failed to update payment batches, rolling back." + ex.Message);
try
{
transaction.Rollback();
}
catch (Exception exRollback)
{
if (!(exRollback is InvalidOperationException)) // connection closed or transaction already rolled back on the server.
{
MessageBox.Show("Failed to roll back. " + exRollback.Message);
}
}
}
}
Since you're repeatedly executing the same query, it's unnecessary to clear them - you can add the parameters outside the loop and just fill them inside.
try
{
command.CommandText = "UPDATE Item SET payment_method_id = #batchID WHERE id in (#itemIDs)";
command.Parameters.Add(new SqlParameter("#batchID", 0));
command.Parameters.Add(new SqlParameter("#itemIDs", ""));
foreach (var itemIDs in this.SelectedItemIds)
{
command.Parameters["#batchID"].Value = batchID;
command.Parameters["#itemIDs"].Value = itemIDs;
command.ExecuteNonQuery();
}
transaction.Commit();
}
Note - you can't use parameters with IN as you've got here - it won't work.
In this condition you need it as you need set new parameters values, so its correct.
By the way, move
command.CommandText = ".."
outside of the loop too, as it's never changed.

Categories

Resources