Second connection object throwing error inside Transaction Scope - c#

I'm developing a desktop application using VS.net and SQL Server. In one of the form, am using Transaction Scope. The code is as follows:-
//Constructor code
InitializeComponent();
ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["dbConSQLServerExp"].ConnectionString;
connectionString2 = System.Configuration.ConfigurationManager.ConnectionStrings["dbConSQLServerExp"].ConnectionString;
//Button save code
string sql1 = #"SELECT sub_id FROM TABLE1 WHERE c_id=#c_id";
try
{
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection con1 = new SqlConnection(connectionString))
{
con1.Open();
using (SqlCommand cmd1 = new SqlCommand(sql1, con1))
{
cmd1.Parameters.Add("#c_id", SqlDbType.Int).Value = clsId;
cmd1.CommandType = CommandType.Text;
using (SqlDataReader rdr1 = cmd1.ExecuteReader())
{
while (rdr1.Read())
{
string sql2 = #"INSERT INTO TABLE2(casm_cls_id,casm_ass_id,casm_subj_text,casm_subj_id,casm_subj_mm)
VALUES(#casm_cls_id,#casm_ass_id,#casm_subj_text,#casm_subj_id,#casm_subj_mm)";
using (SqlConnection con2 = new SqlConnection(connectionString2))
{
con2.Open();
using (SqlCommand cmd2 = new SqlCommand(sql2, con2))
{
cmd2.Parameters.Add("#casm_cls_id", SqlDbType.Int).Value = clsId;
cmd2.Parameters.Add("#casm_ass_id", SqlDbType.Int).Value = assId;
cmd2.Parameters.Add("#casm_subj_text", SqlDbType.VarChar, 20).Value = lvMapList.Items[row].SubItems[4].Text;
cmd2.Parameters.Add("#casm_subj_id", SqlDbType.Int).Value = Convert.ToInt32(rdr1["sub_id"].ToString());
cmd2.Parameters.Add("#casm_subj_mm", SqlDbType.Int).Value = Convert.ToInt32(txtMaxMarks.Text.Trim());
cmd2.CommandType = CommandType.Text;
cmd2.ExecuteNonQuery();
}
}
}
}
}
scope.Complete();
MessageBox.Show("Records added", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch (TransactionAbortedException tex)
{
MessageBox.Show("1-1--->>" + tex.Message);
}
catch (SqlException ex)
{
MessageBox.Show("1-2--->>" + ex.Message);
}
I'm encountering error at
con2.Open();
The error message simply says that the transaction has aborted.
Can anyone please explain what am I doing wrong or whats the correct way to do it?

Related

Cause of 'SqlTransaction has completed' error

I am developing a small desktop application using VS.net and SQL Server.
I am using SqlTransaction in my code:
SqlTransaction tran = null;
SqlCommand cmd = new SqlCommand();
int lstInsSubjId = -1;
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
tran = con.BeginTransaction("Transaction1");//Transaction begin
tran.Save("Savepoint_1");//Savepoint 1
string sql1 = #"insSubject";
cmd = new SqlCommand(sql1, con, tran);
cmd.Parameters.Add("#lstInsSubjId", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("#sub_name", SqlDbType.VarChar).Value = txtSubjectName.Text.Trim();
cmd.CommandType = CommandType.StoredProcedure;
tran.Save("Savepoint_2");//Savepoint 2
cmd.ExecuteNonQuery();
lstInsSubjId = Convert.ToInt32(cmd.Parameters["#lstInsSubjId"].Value);
for (int i = 0; i < clbClasses.CheckedItems.Count; i++)
{
int clsId = Convert.ToInt32(((DataRowView)clbClasses.CheckedItems[i]).Row["c_id"].ToString());
cmd.CommandText = #"INSERT INTO tblClassSubjectMap_mavis(c_id, sub_id)
VALUES(#c_id, #sub_id)";
cmd.Parameters.Add("#c_id", SqlDbType.Int).Value = clsId;
cmd.Parameters.Add("#sub_id", SqlDbType.Int).Value = lstInsSubjId;
cmd.CommandType = CommandType.Text;
//tran.Save("Savepoint_3");//Savepoint 3
cmd.ExecuteNonQuery();
}
tran.Commit();//Transaction commit
MessageBox.Show("Records added", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
txtSubjectName.Text = "";
txtSubjectName.Focus();
frmSubjectBrows.subList.bindListView();
}
}
catch (SqlException ex)
{
if (tran != null)
{
tran.Rollback();
MessageBox.Show(ex.Message.ToString() + "\nTransaction Rolledback", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
Towards the end of the code, in the for loop, if there are more than one checked items i.e. if it iterates/loops more than once then it throws an error and the Transaction is never committed. However, If it loops only once then there is no error and the transactions commits.
The error message is :
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
Additional information: This SqlTransaction has completed; it is no longer usable.
While looking for an answer on the internet, some solutions say that such error may occur if the transaction is abruptly closed before being committed. But I don't understand how here the transaction is getting closed.
Can anyone please tell what is going wrong? Thanks in advance.
use for each command a new instance of sqlcommand, see example at
https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqltransaction?view=netframework-4.8
try this code:
int lstInsSubjId = -1;
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand cmd = connection.CreateCommand();
SqlTransaction tran = con.BeginTransaction("Transaction1");//Transaction begin
cmd.Connection = cmd;
cmd.Transaction = tran;
tran.Save("Savepoint_1");//Savepoint 1
cmd.CommandText = #"insSubject";
cmd.Parameters.Add("#lstInsSubjId", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("#sub_name", SqlDbType.VarChar).Value = txtSubjectName.Text.Trim();
cmd.CommandType = CommandType.StoredProcedure;
tran.Save("Savepoint_2");//Savepoint 2
cmd.ExecuteNonQuery();
lstInsSubjId = Convert.ToInt32(cmd.Parameters["#lstInsSubjId"].Value);
for (int i = 0; i < clbClasses.CheckedItems.Count; i++)
{
int clsId = Convert.ToInt32(((DataRowView)clbClasses.CheckedItems[i]).Row["c_id"].ToString());
SqlCommand cmd2 = connection.CreateCommand();
cmd2.Connection = cmd2;
cmd2.Transaction = tran;
cmd2.CommandText = #"INSERT INTO tblClassSubjectMap_mavis(c_id, sub_id)
VALUES(#c_id, #sub_id)";
cmd2.Parameters.Add("#c_id", SqlDbType.Int).Value = clsId;
cmd2.Parameters.Add("#sub_id", SqlDbType.Int).Value = lstInsSubjId;
cmd2.CommandType = CommandType.Text;
//tran.Save("Savepoint_3");//Savepoint 3
cmd2.ExecuteNonQuery();
}
tran.Commit();//Transaction commit

Why can't I get the current ID and place in another table?

I am attempting to create a simple news and image system, I first need to use SCOPE_IDENTITY() and execute scalar, but I'm not having much luck. I get a:
The name 'newID' does not exist in the current context
protected void btnUpload_Click(object sender, EventArgs e)
{
if (FileUpload1.PostedFile != null)
{
string FileName = Path.GetFileName(FileUpload1.PostedFile.FileName);
//Save files to disk
FileUpload1.SaveAs(Server.MapPath("/images/admin/news/" + FileName));
//Add Entry to DataBase
String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
int newID = 0;
string strQuery = #"insert into tblFiles (FileName, FilePath) values(#FileName, #FilePath); select cast(scope_identity() As int);";
using (SqlConnection connection = new SqlConnection(strConnString))
using (SqlCommand command = new SqlCommand(strQuery, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("#FileName", SqlDbType.VarChar).Value = FileName;
command.Parameters.Add("#FilePath", SqlDbType.VarChar).Value = "/images/admin/news/" + FileName;
try
{
connection.Open();
newID = (int)command.ExecuteScalar();
}
catch
{
}
}
}
if (newID > 0)
{
string strAddNewsQuery = #"insert into tblNews (newsTitle, newsDate, newsSummary, newsContent, newsPicID)
values(#newsTitle, #newsDate, #newsSummary, #newsContent, #newsPicID)";
using (SqlConnection connection = new SqlConnection(strConnString))
using (SqlCommand command = new SqlCommand(strAddNewsQuery, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("#newsTitle", SqlDbType.VarChar).Value = FileName;
command.Parameters.AddWithValue("#newsDate", txtnewsdate.Text);
command.Parameters.AddWithValue("#newsSummary", txtnewssummary.Text);
command.Parameters.AddWithValue("#newsContent", txtnewsmaincontent.Text);
command.Parameters.Add("#newsPicID", SqlDbType.Int).Value = newID;
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch
{
}
finally {
connection.Close();
connection.Dispose();
}
}
}
}
}
An int does not have properties you can access. Change
command.Parameters.AddWithValue("#newsPicID", newID.Value);
into
command.Parameters.AddWithValue("#newsPicID", newID);
Even better is to use parameters with the database value type specified.
command.Parameters.Add("#newsPicID", SqlDbType.Int).Value = newID;
But you are trying to get the SCOPE_IDENTITY() of table tblNews, not from tblFiles to be used in tblNews as newsPicID. You need to get SCOPE_IDENTITY() from the first database command.
UPDATE
And you need to assign the connection to the command.
SqlCommand cmd = new SqlCommand(strQuery, con)
UPDATE 2
Here is a complete snippet to get you started. Notice the wrapping with using. This ensures proper disposal of connections.
int newID = 0;
using (SqlConnection connection = new SqlConnection(strConnString))
using (SqlCommand command = new SqlCommand(strQuery, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("#FileName", SqlDbType.VarChar).Value = FileName;
command.Parameters.Add("#FilePath", SqlDbType.VarChar).Value = "/images/admin/news/" + FileName;
try
{
connection.Open();
newID = (int)command.ExecuteScalar();
}
catch
{
}
}
if (newID > 0)
{
using (SqlConnection connection = new SqlConnection(strConnString))
using (SqlCommand command = new SqlCommand(strAddNewsQuery, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("#newsTitle", SqlDbType.VarChar).Value = FileName;
//etc
command.Parameters.Add("#newsPicID", SqlDbType.Int).Value = newID;
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch
{
}
}
}

"Procedure or function expects parameter which was not supplied."

I'm trying to execute a stored procedure and print the output, but when I run the below code I'm getting error like "Procedure or function 'SPInsertLocal' expects parameter '#RES', which was not supplied."
private void InsertPdtLocal(string code, string PON,string Qty)
{
string str = Properties.Settings.Default.conLocal;
SqlConnection con = new SqlConnection(str);
SqlCommand cmd = new SqlCommand("Execute SPInsertLocal #PON,#TCode,#Qty,#Type", con);
try
{
con.Open();
cmd.CommandTimeout = 150;
cmd.Parameters.AddWithValue("#PON", PON);
cmd.Parameters.AddWithValue("#Qty", Qty);
cmd.Parameters.AddWithValue("#TCode", code);
cmd.Parameters.AddWithValue("#Type", Globals.s_type);
SqlParameter output = new SqlParameter("#RES", SqlDbType.Int);
output.Direction = ParameterDirection.Output;
cmd.Parameters.Add(output);
cmd.ExecuteNonQuery();
con.Close();
int id = Convert.ToInt32(output.Value);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
What I'm doing wrong here?
SqlCommand cmd = new SqlCommand("Execute SPInsertLocal #PON,#TCode,#Qty,#Type,#RES", con);
I was not passing the parameter , fixed the issue
You can refactor the code as follows where the using statement is used for the auto management of connection closing and avoid hardcoding Execute statement in c# code which is a bad practice
private void InsertPdtLocal(string code, string PON,string Qty)
{
string str = Properties.Settings.Default.conLocal;
try
{
using (SqlConnection con = new SqlConnection(str))
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.Parameters.AddWithValue("#PON", PON);
cmd.Parameters.AddWithValue("#Qty", Qty);
cmd.Parameters.AddWithValue("#TCode", code);
cmd.Parameters.AddWithValue("#Type", Globals.s_type);
var output = cmd.Parameters.Add("#RES" , SqlDbType.Int);
output.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
int id = Convert.ToInt32(output.Value);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

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();
}
}
}

Error in server 'executenonquery requires an open and available connection'

I got this error on server not in local and when facing this error, then i re-upload that related class file. after doing this problem solved but not permanently.
Error:
executenonquery requires an open and available connection. The
connection's current state is open.
Code:
int n;
try
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = DataConnection.Con;
cmd.CommandText = "sp_InsertUpdateDeleteValidationDate";
cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 0;
cmd.Parameters.AddWithValue("#Task", "CheckExist");
cmd.Parameters.AddWithValue("#id", 0);
cmd.Parameters.AddWithValue("#AdId", "");
cmd.Parameters.AddWithValue("#Username", "");
cmd.Parameters.AddWithValue("#DOE", DOE);
cmd.Parameters.AddWithValue("#ExpieryDate", DateTime.Now);
cmd.Parameters.AddWithValue("#DOR", DateTime.Now);
cmd.Parameters.Add("#flag", SqlDbType.Int).Direction = ParameterDirection.Output;
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
cmd.ExecuteNonQuery();
n = Convert.ToInt32(cmd.Parameters["#flag"].Value);
return n;
}
}
catch (SqlException Ex)
{
return 0;
}
You only create one connection in your DataConnection class. You should create a new connection for each database call and let the driver's connection pooling take care of efficiently reusing them.
change your DataConnection class to this:
public class DataConnection
{
public static SqlConnection Con
{
get
{
return new SqlConnection(ConfigurationManager
.ConnectionStrings["conn"].ConnectionString);
}
}
}
and use a using statement when you use the connection like in ekad's answer:
using (SqlConnection conn = DataConnection.Con)
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
//use the command here
}
}
Looks like your SqlConnection is never closed. Try to use using statement to make sure that the SqlConnection is closed after executing cmd.ExecuteNonQuery()
int n;
try
{
using (SqlConnection conn = DataConnection.Con)
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "sp_InsertUpdateDeleteValidationDate";
cmd.CommandType = CommandType.StoredProcedure; cmd.CommandTimeout = 0;
cmd.Parameters.AddWithValue("#Task", "CheckExist");
cmd.Parameters.AddWithValue("#id", 0);
cmd.Parameters.AddWithValue("#AdId", "");
cmd.Parameters.AddWithValue("#Username", "");
cmd.Parameters.AddWithValue("#DOE", DOE);
cmd.Parameters.AddWithValue("#ExpieryDate", DateTime.Now);
cmd.Parameters.AddWithValue("#DOR", DateTime.Now);
cmd.Parameters.Add("#flag", SqlDbType.Int).Direction = ParameterDirection.Output;
conn.Open();
cmd.ExecuteNonQuery();
n = Convert.ToInt32(cmd.Parameters["#flag"].Value);
return n;
}
}
}
catch (SqlException Ex)
{
return 0;
}

Categories

Resources