Applying transaction on multiple SQL queries - c#

How can i use transaction in single function for multiple insert and update queries? for example:
private void button1_Click(object sender, EventArgs e)
{
// transaction
SqlConnection objConnection = new SqlConnection(annual_examination_system.Properties.Settings.Default.connString);
SqlTransaction objTransaction = null;
int count = 0;
try
{
objConnection.Open();
objTransaction = objConnection.BeginTransaction();
string q1 = "update query"
SqlCommand objCommand1 = new SqlCommand(q1, objConnection, objTransaction);
objCommand1.ExecuteNonQuery();
objTransaction.Commit();
string q2 = "insert query"
SqlCommand objCommand1 = new SqlCommand(q2, objConnection, objTransaction);
objCommand1.ExecuteNonQuery();
objTransaction.Commit();
}
catch (Exception ex)
{
objTransaction.Rollback();
MessageBox.Show(ex.Message);
MessageBox.Show("Exception, Row :" + count);
MessageBox.Show("Transaction Rollback.");
}
finally
{
// Close the connection.
if (objConnection.State == ConnectionState.Open)
{
objConnection.Close();
}
}
now there are two queries one is for update and one is for insert. so do i have to apply transaction separately on them or one transaction can be applied on both?

You can use same transaction for both queries .
Here is an example :
SqlTransaction tran;
Now using this for both the queries
using(SqlConnection connection=new SqlConnection(connection_string))
{
connection.Open();
tran = connection.BeginTransaction();
cmd = new SqlCommand(query1, connection, tran);
cmd1 = new SqlCommand(query2, connection, tran);
count = cmd.ExecuteNonQuery();
count = count + cmd1.ExecuteNonQuery();
tran.Commit();
}
Update : connection is not closing that's the problem. I have edited the code. Please see the update.

Related

How to properly execute a linked server stored procedure from C#

I want to execute an stored procedure located in a linked server database. Currently, I'm using this in SSMS:
INSERT INTO myTable
EXEC [LINKEDSERVER\LINKED].[Data_Base_Name].[Store].usp_GetInfo 1, 1, NULL, 'H'
This will insert into my Local DB the result data from the Stored procedure located in LINKEDSERVER\LINKED.
I want to be able to do this with a command from C#, is there a proper way to do it?
Thanks!
You could execute SP from DataContext:
using (DataContext ctx = DataContext())
{
int result = ctx.SP_ProcedureName("1", "2", "3");
}
But first you have to add it to DataContext Diagram from your database as you add tables but from "Stored Procedures" folder.
that is more defensive and neat solution. but if you prefer to use raw command line at least use parameterized query for it like this example :
string sqlText = "SELECT columnName FROM Test_Attachments WHERE Project_Id =#PID1 AND [Directory] = #Directory";
SqlCommand myCommand = new SqlCommand(sqlText, SqlConnection);
myCommand.Parameters.AddWithValue("#PID1", 12);
myCommand.Parameters.AddwithValue("#Directory", "testPath");
It is way for avoiding SQL injection to your code.
Also you could use finally block for close connection :
finally
{
command.Connection.Close();
}
Thank you guys for the help. Oleg thanks for your suggestion as well. What I did was this:
qSQL = "INSERT INTO " + tableName + " EXEC [LINKEDSERVER\\LINKED].[Data_Base_Name]." + spName;
using (SqlConnection _connection = new SqlConnection(connectionString))
{
try
{
command = new SqlCommand();
command.Connection = _connection;
command.Connection.Open();
command.CommandText = _qSQL;
command.CommandTimeout = 300; //Because it takes long
SqlTransaction transaction;
transaction = connection.BeginTransaction();
try
{
command.Transaction = _transaction;
command.ExecuteNonQuery();
transaction.Commit();
Debug.WriteLine("Done");
}
catch (SqlException e)
{
Debug.WriteLine("Exception [{0}:{1}]", e.Number, e.Message);
transaction.Rollback();
}
//close connection
command.Connection.Close();
}
catch (SqlException e)
{
command.Connection.Close();
Debug.WriteLine("exception error number: " + e.Number + ": " + e.Message);
}
}
}
If you have any suggestions to improve this let me know.

Works perfectly except changes are not saved to the SQL database

Changes are not saved to the SQL database
Why would I want to use '#' in the sql statement instead of the way that I have the statement?
Code:
private void button_Save_Customer_Click(object sender, EventArgs e)
{
sqlString = Properties.Settings.Default.ConnectionString;
SqlConnection sqlConnection = new SqlConnection(sqlString);
try
{
string customer_Ship_ID = customer_Ship_IDTextBox.ToString();
string customer_Ship_Address = customer_Ship_AddressTextBox.Text;
SQL = "UPDATE Customer_Ship SET Customer_Ship_Address = customer_Ship_Address WHERE Customer_Ship_ID = customer_Ship_ID";
SqlCommand sqlCommand = new SqlCommand(SQL, sqlConnection);
sqlCommand.Parameters.AddWithValue("Customer_Ship_ID", customer_Ship_ID);
sqlCommand.Parameters.AddWithValue("Customer_Ship_Address", customer_Ship_Address);
sqlCommand.CommandText = SQL;
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
MessageBox.Show("Record Updated");
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
Here you can check the MSDN reference for the update command.
Use parameters, Why?
Also check that you need to open and close the connection object, not the command.
In case you want to update the rows with the Customer_ID = "something" you could do like this:
The code (updated after your changes):
private void button_Save_Customer_Click(object sender, EventArgs e)
{
string sqlString = Properties.Settings.Default.ConnectionString;
SqlConnection sqlConnection = new SqlConnection(sqlString);
try
{
int customer_Ship_ID;
if(int.TryParse(customer_Ship_IDTextBox.Text, out customer_Ship_ID))
{
string customer_Ship_Address = customer_Ship_AddressTextBox.Text;
// Customer_Ship: Database's table
// Customer_Ship_Address, Customer_Ship_ID: fields of your table in database
// #Customer_Ship_Address, #Customer_Ship_ID: parameters of the sqlcommand
// customer_Ship_ID, customer_Ship_Address: values of the parameters
string SQL = "UPDATE Customer_Ship SET Customer_Ship_Address = #Customer_Ship_Address WHERE Customer_Ship_ID = #Customer_Ship_ID";
SqlCommand sqlCommand = new SqlCommand(SQL, sqlConnection);
sqlCommand.Parameters.AddWithValue("Customer_Ship_ID", customer_Ship_ID);
sqlCommand.Parameters.AddWithValue("Customer_Ship_Address", customer_Ship_Address);
sqlCommand.CommandText = SQL;
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
sqlConnection.Close();
MessageBox.Show("Record Updated");
}
else
{
// The id of the textbox is not an integer...
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
Seems like your syntax isn't correct. Here's the syntax for the Update:
UPDATE table_name
SET column1=value1,column2=value2,...
WHERE some_column=some_value;
So, Update, what to set, and WHERE to set (which you seem to be missing).
For more, have a look here.
Check your update query
Change it like
string SQL = string.format("UPDATE Customer_Ship SET Customer_Ship_Address='{0}'",putUrVaue);

Sending several SQL commands in a single transaction

I have a huge list of INSERT INTO ... strings. Currently I run them with:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
foreach (var commandString in sqlCommandList)
{
SqlCommand command = new SqlCommand(commandString, connection);
command.ExecuteNonQuery();
}
}
I see that each ExecuteNonQuery() also executes commit.
Is there a way to insert all rows in a single transaction (commit in the end)?
The reason I want a single transaction is to make my "inserts" process faster. Will a single transaction also make it quicker?
Its recommended to use SQL transaction in case you are executing Multiple queries in one thread , you can have it like this :
SqlTransaction trans;
try
{
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
trans = connection.BeginTransaction();
foreach (var commandString in sqlCommandList)
{
SqlCommand command = new SqlCommand(commandString, connection,trans);
command.ExecuteNonQuery();
}
trans.Commit();
}
catch (Exception ex) //error occurred
{
trans.Rollback();
//Handel error
}
You might probably gain some performance by using just one single transaction and command, as follows:
using (SqlConnection connection = new SqlConnection(connectionString))
{
try
{
connection.Open();
using (SqlTransaction trans = connection.BeginTransaction())
{
using (SqlCommand command = new SqlCommand("", connection,trans))
{
command.CommandType = System.Data.CommandType.Text;
foreach (var commandString in sqlCommandList)
{
command.CommandText = commandString;
command.ExecuteNonQuery();
}
}
trans.Commit();
}
}
catch (Exception ex) //error occurred
{
//Handel error
}
}
A little late, but if you are inserting all of the values into the same table, code the SQL insert as "insert into tablex (f1, f2, f3,...) values (#F1,#F2,#F3...)". Create the command and add the parameters #F1..., and then set the Prepare flag on the command. Now as you loop through your list of values to insert, you can set them into the appropriate parameters and then do the ExecuteNonQuery. SQL will pre-parse the command string once, and then use the new parameters each time. This is a bit faster.
Finally, you can execute multiple SQL statements in a single command by appending ';' to each statement, if you must execute the entire string. You can bunch a number of these commands together and make one request to SQL server to execute them.
You can just concatenate the sql and let the server handle it:
using (SqlConnection connection = new SqlConnection(connectionString))
{
string lsSql = string.Empty;
foreach (var commandString in sqlCommandList)
{
lsSql = lsSql + commandString + " ; " + Environment.NewLine;
}
connection.Open();
SqlCommand command = new SqlCommand(lsSql, connection);
command.ExecuteNonQuery();
}
Here is what I use on my daily work, before it a use a foreach for any non-query that I need to run on database. You can see that I'm using the OracleCommand, but if you need you can change to SQL statement
public static void ExecuteDatabaseNonQuery(string command)
{
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
OracleTransaction transaction;
transaction = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Transaction = transaction;
try
{
cmd.CommandText = command;
var update = cmd.ExecuteNonQuery();
transaction.Commit();
Console.WriteLine("{0} rows updated", update);
}
catch (Exception e)
{
transaction.Rollback();
throw new Exception("Error: " + e);
}
}
Note: If theres any uncommited changes on database this method will wait indefinitely
You can use Parallel for each
using (SqlConnection connection = new SqlConnection(connectionString))
{
List<string> sqlCommandList = new List<string>();
connection.Open();
Parallel.ForEach(sqlCommandList, commandString =>
{
SqlCommand command = new SqlCommand(commandString, connection);
command.ExecuteNonQuery();
});
}

Multiple Sql Insert String And RollBack With Catch(Exception)

If I have to insert with two sql table and the place of string is as below:
// Single Record Insert
String AA=”Insert into aa(date)values(#date)”;
//Multiple Record Insert with datagridview1
For(int i=0;i<datagridview1.rows.count-1;i++)
{
String BB= “insert into bb(name,amount)values(#name,#amount)”;
}
If there are two different strings of sql insert as per as above by single and multiple insert on Button click Event than Is it possible to handle it on single sql command if yes than reply how?.
But as per I think it is not possible by single SqlCommand and if it is true than there are very big problem to adjust SqlTransaction Class for Rollback and Commit. with try and catch block of the EventHandller
I am really struggling to insert multiple sql statement as above at one Button1_Click Event. Suggest me proper solution or proper way , technique.
You can explicitly define the transactions in your ADO.NET Code.
private void button1_Click(object sender, EventArgs e)
{
SqlConnection db = new SqlConnection("constring");
SqlCommand com = new SqlCommand();
SqlCommand com2 = new SqlCommand();
SqlTransaction tran;
db.Open();
tran = db.BeginTransaction();
try
{
//Run all your insert statements here here
com.CommandText = "Insert into a(Date) Values(#Date)";
com.Connection = db;
com.Transaction = tran;
com.Parameters.Add("#Date", SqlDbType.DateTime);
com.Parameters["#Date"].Value = DateTime.Now;
com.ExecuteNonQuery();
com2.CommandText = "Insert into bb(name,amount) values(#name, #amount)";
com2.Connection = db;
com2.Transaction = tran;
com2.Parameters.Add("#name", SqlDbType.VarChar, 25);
com2.Parameters.Add("#amount", SqlDbType.Decimal);
for (int i = 0; i < datagrid.Rows.Count; i++)
{
//on each loop replace #name value and #amount value with appropiate
//value from your row collection
com2.Parameters["#name"].Value = datagrid.Rows[i].Cells["Name"].Value;
com2.Parameters["#amount"].Value = datagrid.Rows[i].Cells["Amount"].Value;
com2.ExecuteNonQuery();
}
tran.Commit();
}
catch (SqlException sqlex)
{
tran.Rollback();
}
finally
{
db.Close();
}
}

how to use sql.trans in two methods?

i have cut and paste buttons while cutting i have one sql operation and while pasting one sql operation . how to use transation statement for this .
protected void btnCut_Click(object sender, EventArgs e)
{
hidCutnode.Value = TreeView2.SelectedNode.Value;
string sqlQuery = "update CUSTOMIZEDTREE set parentid='" + 0 + "' where nodeid='" + hidCutnode.Value + "'";
string connectionString = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.69.200.62)(PORT=1521)))(CONNECT_DATA=(SID=orcl)));User Id=apex_demo;Password=apex_demo;";
OracleConnection con = new OracleConnection(connectionString);
con.Open();
tran = con.BeginTransaction();
OracleCommand cmd = new OracleCommand(sqlQuery, con);
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
con.Close();
}
protected void btnPaste_Click(object sender, EventArgs e)
{
hidPastenode.Value = TreeView2.SelectedNode.Value;
try
{
string sqlQuery = "update CUSTOMIZEDTREE set parentid='" + hidPastenode.Value + "' where nodeid='" + hidCutnode.Value + "'";
string connectionString = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.69.200.62)(PORT=1521)))(CONNECT_DATA=(SID=orcl)));User Id=apex_demo;Password=apex_demo;";
OracleConnection con = new OracleConnection(connectionString);
con.Open();
OracleCommand cmd = new OracleCommand(sqlQuery, con);
tran = con.BeginTransaction();
// cmd.Connection = con;
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
tran.Commit();
con.Close();
PopulateCustomTree();
}
catch (Exception ex)
{
tran.Rollback();
ex.ToString();
}
}
Pass transaction object as function parameter to the second method and dont commit in method1. Use BeginTransaction in first method only.
SqlTransaction trn = connect.BeginTransaction();
try
{
SqlCommand command = new SqlCommand(query);
command.Transaction = trn;
command.Connection = connect;
connect.Open();
command.CommandTimeout = 0;
command.ExecuteNonQuery();
trn.Commit();
}
catch (Exception ex)
{
trn.Rollback();
}
connect.Close();

Categories