Second query failed to update because first query still in insert progress - c#

private void btnSave_Click(object sender, EventArgs e)
{
using (OleDbConnection con = new OleDbConnection(cs))
{
con.Open();
cmd = new OleDbCommand(“INSERT INTO table1 ([name], [gender], [age]) VALUES ('Jeff', 'Male', 51), con);
cmd.ExecuteNonQuery();
//System.Threading.Thread.Sleep(1000); // it's working if i add a delay here
//int success = cmd.ExecuteNonQuery(); // also working if check number of query affected
//if (success > 0)
//{
// updateLastModified();
//}
updateLastModified();
}
}
public void updateLastModified()
{
using (OleDbConnection con = new OleDbConnection(cs))
{
con.Open();
cmd = new OleDbCommand("UPDATE TABLE1 SET LastModifiedTime='" + DateTime.Now.ToString() + "' WHERE name='Jeff'", con);
cmd.ExecuteNonQuery();
// this was not updated because "Jeff" cannot be found in table1 (first insert query still running)
}
}
My problem was second query not updated because first query still running.
Any better solution other than "adding a delay" or "check first query was successful" before perform second query?
This is just an example scenario, I'm not going to do in one query.
Update:
Suggestion from #a.rlx was using OleDbTransaction.Commit method. Can i do by this way without using try catch?
using (OleDbConnection con = new OleDbConnection(cs))
{
OleDbTransaction transaction = null;
con.Open();
transaction = con.BeginTransaction();
cmd = new OleDbCommand(“INSERT INTO table1 ([name], [gender], [age]) VALUES ('Jeff', 'Male', 51), con, transaction);
cmd.ExecuteNonQuery();
transaction.Commit();
updateLastModified();
}

Have you tried to start a transaction, run both SQL statements, and then commit the transaction?
https://dev.mysql.com/doc/dev/connector-net/6.10/html/M_MySql_Data_MySqlClient_MySqlConnection_BeginTransaction.htm

Related

Syntax error in update using C# inputting data into an existing row

I am having problem with my code with the update query it shows the error syntax error in update statement. I would like to insert in data into an existing row with the columns already created.
private void save_care_Click(object sender, EventArgs e)
{
if (textBox2.Text=="")
{
//Checking if workorder exist in database
connection.Open();
OleDbCommand checkrecord = new OleDbCommand("SELECT COUNT(*) FROM [c# barcode] WHERE ([Workorder] = #workorder)", connection);
checkrecord.Parameters.AddWithValue("#workorder", textBox2.Text);
int recordexist = (int)checkrecord.ExecuteScalar();
if (recordexist > 0)
{
//add data if it exist
string cmdText = "UPDATE [c# barcode] SET ([Close from care],[Name care]) VALUES (#Close, #name) WHERE ([Workorder] = #workorder)";
using (OleDbCommand cmd = new OleDbCommand(cmdText, connection))
{
cmd.Parameters.AddWithValue("#workorder", textBox2.Text);
cmd.Parameters.AddWithValue("#Close", DateTime.Now.ToString("d/M/yyyy"));
cmd.Parameters.AddWithValue("#name", label4.Text);
cmd.ExecuteNonQuery();
textBox2.Clear();
connection.Close();
}
connection.Close();
}
else
{
//inserting workorder if it does not exist
string cmdText = "INSERT INTO [c# barcode] ([Workorder], [Close from care], [Name care]) VALUES (#workorder, #Close, #name)";
using (OleDbCommand cmd = new OleDbCommand(cmdText, connection))
{
cmd.Parameters.AddWithValue("#workorder", textBox2.Text);
cmd.Parameters.AddWithValue("#Close", DateTime.Now.ToString("d/M/yyyy"));
cmd.Parameters.AddWithValue("#name", label4.Text);
if (cmd.ExecuteNonQuery() > 0)
{
textBox2.Clear();
MessageBox.Show("Insert successful, workorder has not been handed over, please check");
}
else
{
textBox2.Clear();
MessageBox.Show("Please rescan");
connection.Close();
}
connection.Close();
}
}
}
else
MessageBox.Show("No data, Please scan workorder");
}
Error is at cmd.ExecuteNonQuery(); line.
For example the table in the picture under workorder there is a test4 the update will insert data into the column [Close from care] and [name care] in the test4 row
I believe that you are using the INSERT syntax for an UPDATE. You should use the UPDATE syntax.
The example from Microsoft is as follows:
UPDATE Orders
SET OrderAmount = OrderAmount * 1.1,
Freight = Freight * 1.03
WHERE ShipCountry = 'UK';
So if we update yours to match, it should look like this:
UPDATE [c# barcode]
SET [Close from care] = #Close,
[Name care] = #name
WHERE [Workorder] = #workorder
Obviously the newlines aren't important, it's just to make it easier to read.

Conditional SQL statement - switching between insert/update query [duplicate]

This question already has answers here:
Upserting in MS-access
(6 answers)
Closed 9 years ago.
Is there a way to insert if/else clause into the following line here:
command.CommandText = "UPDATE Table1 SET ID=value1,Team=value2 WHERE ID=value3";
In a case where ID=value3 (in other words the row already exists) can be found then an update query takes place but where it cannot be found I want an insert query to take place:
command.CommandText = "INSERT INTO Table1 (ID,Team) VALUES (value1,value2)";
to take place... how can I do that?
private void button1_Click(object sender, EventArgs e)
{
// save to access database when user clicks on the save button
using (OleDbConnection conn = new OleDbConnection())
{
//the file path of mdb
string filepath = #"C:\Users\sy\Visual Studio 2008\Projects\demo\demo\CE_Database.mdb";
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;data source=" + filepath + ";";
OleDbCommand command = new OleDbCommand();
command.Connection = conn;
//your update satemenet
command.CommandText = "UPDATE Table1 SET ID=value1,Team=value2 WHERE ID=value3";
conn.Open();
//update to ms access
command.ExecuteNonQuery();
conn.Close();
}
}
Since command.ExecuteNonQuery(); will return the number of rows affected, you can check what this returns from the update command, if the record does not exist the method will return 0, then you can then progress to the insert method:
private string filepath = #"C:\Users\sy\Visual Studio 2008\Projects\demo\demo\CE_Database.mdb";
private string connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;data source=" + filepath + ";";
private void button1_Click(object sender, EventArgs e)
{
if (this.Update() == 0)
{
this.Insert();
}
}
private int Update()
{
using (OleDbConnection conn = new OleDbConnection(connectionString))
using (OleDbCommand command = new OleDbCommand("UPDATE Table1 SET ID=value1,Team=value2 WHERE ID=value3", conn);
{
conn.Open();
return command.ExecuteNonQuery();
}
}
private int Insert()
{
using (OleDbConnection conn = new OleDbConnection(connectionString))
using (OleDbCommand command = new OleDbCommand("INSERT INTO Table1 (ID,Team) VALUES (value1,value2)", conn);
{
conn.Open();
return command.ExecuteNonQuery();
}
}
To clear up comments on the answer, the OleDbConnection.Dispose() method looks like this:
protected override void Dispose(bool disposing)
{
if (disposing)
{
this._userConnectionOptions = null;
this._poolGroup = null;
this.Close();
}
this.DisposeMe(disposing);
base.Dispose(disposing);
}
So the connection will be closed by the Dispose method, so there is no need to explicitly call Close() when your connection is in a using block
Sounds like you're after the MERGE statement... which doesn't exist in the JET version of SQL. This'll work for most things though:
UPDATE Table1 RIGHT JOIN Table2
ON Table1.[KeyField] = Table2.[KeyField]
SET Table1.[KeyField] = Table2.[KeyField],
Table1.[OtherField] = Table2.[OtherField]
If it is in Table2, it will be inserted into Table1, overwriting the value (updating), if it's already in Table1.
It's simple. Check for the existence of ID = 3 through a SELECT COUNT(*) query before running INSERT or UPDATE.
You could do the UPDATE query first with ExecuteNonQuery(), which returns the number of affected rows.
If affected rows are 0, then you'll run your INSERT query.
//the file path of mdb
string filepath = #"C:\Users\sy\Visual Studio 2008\Projects\demo\demo\CE_Database.mdb";
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;data source=" + filepath + ";";
OleDbCommand command = new OleDbCommand();
command.Connection = conn;
//your update satemenet
command.CommandText = "UPDATE Table1 SET ID=value1,Team=value2 WHERE ID=value3;";
conn.Open();
//update to ms access
int affectedRows = command.ExecuteNonQuery(); // returns 1 if the row exist, 0 if it does not.
if (affectedRows == 0)
{
command.CommandText = "INSERT INTO Table1 (ID,Team) VALUES (value1,value2)";
command.ExecuteNonQuery(); // perform insert
}
conn.Close()
EDIT: As Gord Thompson pointed out, the original solution did not work. ExecuteScalar() with "UPDATE .....; SELECT ##ROWCOUNT". Changed this to use ExecuteNonQuery, and get the number of affected rows from that method.
Old solution using ##ROWCOUNT:
command.CommandText = "UPDATE Table1 SET ID=value1,Team=value2 WHERE ID=value3; SELECT ##ROWCOUNT;";
conn.Open();
//update to ms access
int affectedRows = (int)command.ExecuteScalar(); // returns 1 if the row exist, 0 if it does not.
if (affectedRows == 0)
{
command.CommandText = "INSERT INTO Table1 (ID,Team) VALUES (value1,value2)";
command.ExecuteNonQuery(); // perform insert
}
Use ##ROWCOUNT
command.CommandText = "UPDATE Table1 SET ID=value1,Team=value2 WHERE ID=value3 IF ##ROWCOUNT = 0 INSERT INTO Table1 (ID,Team) VALUES (value1,value2)"
Edit: As Gord said this won't work, I was too fast, didn't notice it's Access.
This is a similar question and solution.

using the same instance of SQLCommand more than one time in the same code for more than one query?

I have question about using why i can not use the same instance of SQLCommand more than one time in the same code?
I tried the code down here and it runs good for the gridview but when i changed the query by using cmd.CommandText() method it keeps saying:
There is already an open DataReader associated with this Command which must be closed first.
This is the code:
string cs = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
SqlConnection con = new SqlConnection(cs);
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = "Select top 10 FirstName, LastName, Address, City, State from Customers";
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
cmd.CommandText = "SELECT TOP 10 COUNT(CreditLimit) FROM Customers";
int total = (int)cmd.ExecuteScalar();
TotalCreditLble.Text = "The total Credit :" + total.ToString();
}
catch(Exception exp)
{
Response.Write(exp.Message);
}
finally
{
con.Close();
}
The problem is that you are using the SqlCommand object to generate a DataReader via the command.ExecuteReader() command. While that is open, you can't re-use the command.
This should work:
using (var reader = cmd.ExecuteReader())
{
GridView1.DataSource = reader;
GridView1.DataBind();
}
//now the DataReader is closed/disposed and can re-use command
cmd.CommandText = "SELECT TOP 10 COUNT(CreditLimit) FROM Customers";
int total = (int)cmd.ExecuteScalar();
TotalCreditLble.Text = "The total Credit :" + total.ToString();
There is already an open DataReader associated with this Command which must be closed first.
This is the very reason you don't share a command. Somewhere in your code you did this:
cmd.ExecuteReader();
but you didn't leverage the using statement around the command because you wanted to share it. You can't do that. See, ExecuteReader leaves a connection to the server open while you read one row at a time; however that command is locked now because it's stateful at this point. The proper approach, always, is this:
using (SqlConnection c = new SqlConnection(cString))
{
using (SqlCommand cmd = new SqlCommand(sql, c))
{
// inside of here you can use ExecuteReader
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// use the reader
}
}
}
These are unmanaged resources and need to be handled with care. That's why wrapping them with the using is imperative.
Do not share these objects. Build them, open them, use them, and dispose them.
By leveraging the using you will never have to worry about getting these objects closed and disposed.
Your code, written a little differently:
var cs = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
var gridSql = "Select top 10 FirstName, LastName, Address, City, State from Customers";
var cntSql = "SELECT TOP 10 COUNT(CreditLimit) FROM Customers";
using (SqlConnection con = new SqlConnection(cs))
{
con.Open();
try
{
using (SqlCommand cmd = new SqlCommand(gridSql, con))
{
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
}
using (SqlCommand cmd = new SqlCommand(cntSql, con))
{
int total = (int)cmd.ExecuteScalar();
TotalCreditLble.Text = "The total Credit :" + total.ToString();
}
}
catch(Exception exp)
{
Response.Write(exp.Message);
}
}
Thank u quys but for the guys who where talking about using block !
why this code work fine which i seen it on example on a video ! It's the same thing using the same instance of SqlCommand and passing diffrent queries by using the method CommanText with the same instance of SqlCommand and it's execute just fine , this is the code :
using (SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = "Delete from tbleProduct where ProductID= 4";
int TotalRowsAffected = cmd.ExecuteNonQuery();
Response.Write("Total rows affected :" + TotalRowsAffected );
cmd.CommandText = "Insert into tbleProduct values (4, 'Calculator', 100, 230)";
TotalRowsAffected = cmd.ExecuteNonQuery();
Response.Write("Total rows affected :" + TotalRowsAffected );
cmd.CommandText = "ypdate tbleProduct set QtyAvailbe = 234 where ProductID = 2";
TotalRowsAffected = cmd.ExecuteNonQuery();
Response.Write("Total rows affected :" + TotalRowsAffected );
}

If not exists then insert else show message "Already exists"

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace Barcode
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string strconn = #"Data Source=ASHWINI-LAPY\SQLEXPRESS;Initial Catalog=complete;Integrated Security=True;Pooling=False";
SqlDataReader reader = null;
SqlConnection conn = null;
conn = new SqlConnection(strconn);
conn.Open();
DateTime Dt_Time = DateTime.Now;
string Barcode = textBox1.Text;
SqlCommand cmd = new SqlCommand("select Barcode from table3 where #Barcode='" + textBox1.Text + "'", conn);
cmd.Parameters.AddWithValue("#Barcode", textBox1.Text);
reader = cmd.ExecuteReader();
if (reader != null && reader.HasRows)
{
//email exists in db do something
MessageBox.Show("Barcode Already Exists!!");
}
else
{
string strquery = string.Format("insert into table3 values('{0}','{1}')", Barcode, Dt_Time);
cmd = new SqlCommand(strquery, conn);
int count = (int)cmd.ExecuteNonQuery();
MessageBox.Show("Barcode:" + Barcode +
"\nTime" + Dt_Time);
}
I am new to C# coding so I tried to do it like what I mentioned below in code, so please somebody help me.
I want to insert a barcode manually and when I press button the SQL Server database has to be checked whether that barcode exists. If not, it has to insert that barcode into the database, but if it already exists, it has to give a message that barcode already exists!
Along with inserting barcode I am also inserting system date and time also in database.
EDIT
C# code that you can write in your button click event
using (System.Data.SqlClient.SqlConnection cn =
new System.Data.SqlClient.SqlConnection(#"Data Source=ASHWINI-LAPY\SQLEXPRESS;Initial Catalog=complete;Integrated Security=True;Pooling=False"+
"Integrated Security=True"))
{
using (System.Data.SqlClient.SqlCommand cmd= new System.Data.SqlClient.SqlCommand("IsBarcodeCheckAndInsert", cn))
{
cmd.CommandType=CommandType.StoredProcedure ;
SqlParameter parm= new SqlParameter("#BarCode", cn",SqlDbType.VarChar) ;
parm.Value="ALFKI";
parm.Size=25;
parm.Direction =ParameterDirection.Input ;
cmd.Parameters.Add(parm);
SqlParameter parm2=new SqlParameter("#IsExists",SqlDbType.Int);
parm2.Direction=ParameterDirection.Output;
cmd.Parameters.Add(parm2);
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
int IsExists = Convert.ToInt32(cmd.Parameters["#IsExists"].Value.ToString());
if(IsExists ==0)
MessageBox.Show("Barcode Already Exists !!");
else if(IsExists ==1)
MessageBox.Show("Barcode not Exists And Inserted In DataBase!!");
}
}
SQL Procdure
CREATE PROCEDURE [dbo].[IsBarcodeCheckAndInsert]
(
#BarCode AS VARCHAR(25),
#IsExists AS INT out )
AS
BEGIN
IF EXISTS (SELECT * FROM table3 WHERE BarCode = #BarCode )
BEGIN
set #IsExists =1
END
ELSE
BEGIN
Insert into table3 values(#BarCode ,getDate())
set #IsExists =0
END
END
Whats wrong with the code I check your code code is fine ..if it's not working at you end what error you are getting.
Just on recommandation make use of SQLParameter in your second queryi.e in insert query also to avoid SQLInjection attack for more detail check here : How does SQLParameter prevent SQL Injection?
Check out these lines of code:
string Barcode = textBox1.Text;
SqlCommand cmd = new SqlCommand("select Barcode from table3 where #Barcode='" + textBox1.Text + "'", conn);
cmd.Parameters.AddWithValue("#Barcode", textBox1.Text);
If textBox1.Text is equal to "example", the resulting SQL query would be
Select Barcode from table3 where 'example'='example'
You might want to change the SqlCommand statement to:
SqlCommand cmd = new SqlCommand("select Barcode from table3 where Barcode=#Barcode", conn);
You can do something like this:
SqlCommand cmd = new SqlCommand("select Barcode from table3 where Barcode=#Barcode", conn);
cmd.Parameters.AddWithValue("#Barcode", textBox1.Text);
Regards
You mixed up your sql parameters syntax, this:
SqlCommand cmd = new SqlCommand("select Barcode from table3 where #Barcode='" + textBox1.Text + "'", conn);
cmd.Parameters.AddWithValue("#Barcode", textBox1.Text);
Should be changed to be like this:
SqlCommand cmd = new SqlCommand("select Barcode from table3 where Barcode = #Barcode", conn);
cmd.Parameters.AddWithValue("#Barcode", textBox1.Text);
Basically you switched the column name with the parameter name in the query.
UPDATE
As for the "There is already an open DataReader..." exception, adjust the code with using blocks (in a "best practice" approach), like this:
private void button1_Click(object sender, EventArgs e)
{
string strconn = "<connection string";
using (SqlConnection conn = new SqlConnection(strconn))
{
bool readerHasRows = false; // <-- Initialize bool here for later use
DateTime Dt_Time = DateTime.Now;
string Barcode = textBox1.Text;
string commandQuery = "SELECT Barcode FROM table3 WHERE Barcode = #Barcode";
using(SqlCommand cmd = new SqlCommand(commandQuery, conn))
{
cmd.Parameters.AddWithValue("#Barcode", textBox1.Text);
using(SqlDataReader reader = cmd.ExecuteReader())
{
// bool initialized above is set here
readerHasRows = (reader != null && reader.HasRows);
}
}
if (readerHasRows)
{
//email exists in db do something
MessageBox.Show("Barcode Already Exists!!");
}
else
{
//Same as above
string strquery = "INSERT INTO table3 VALUES (#Barcode, #DtTime)"; // '{0}','{1}')", Barcode, Dt_Time);
using (SqlCommand cmd = new SqlCommand(strquery, conn))
{
cmd.Parameters.AddWithValue("Barcode", Barcode);
cmd.Parameters.AddWithValue("DtTime", Dt_Time);
int count = cmd.ExecuteNonQuery(); // this already the number of affected rows by itself
// NOTE: '\n' doesn't really work to output a line break.
// Environment.NewLine should be used.
MessageBox.Show("Barcode:" + Barcode + Environment.NewLine + "Time" + Dt_Time);
}
// code probably goes on ...
} // end of using(SqlConnection...
} // end of method
Should at least lead you on the right track.
You can do this in one sql query with the Merge-command.
In plain SQL it will look like:
merge table3 WITH(HOLDLOCK) as target
using (SELECT #Barcode, #DtTime)
as source (Barcode, DtTime)
on target.Barcode = #Barcode
when not matched then
insert ( Barcode, DtTime)
values ( #Barcode, #DtTime);

ASP.net why are these queries not executing?

In my code neither of these queries appear to be running. The debug label is printing as "end" so it is executing something inside that code block, just appears it doesn't like the queries?
// Check input is all valid
if (Page.IsValid)
{
debug.Text = "begin";
using (SqlConnection cn = new SqlConnection(
ConfigurationManager.ConnectionStrings["LocalSqlServer"].ToString()))
{
// Verify that username is unique
using (SqlCommand cmd = new SqlCommand(
"UPDATE tblSiteSettings SET isActive = 0", cn))
{
cn.Open();
cn.Close();
}
using (SqlCommand cmd = new SqlCommand(
"INSERT INTO tblSiteSettings (allowProductRatings, allowComments, " +
"siteName, settingDate, isActive) VALUES (#allowRatings, " +
"#allowcomments, #siteName, getDate(), 1)", cn))
{
cmd.Parameters.Add("#allowRatings", SqlDbType.Bit).Value = 1;
cmd.Parameters.Add("#allowcomments", SqlDbType.Bit).Value = 1;
cmd.Parameters.Add("#siteName", SqlDbType.VarChar, 128).Value = "lol";
cn.Open();
cn.Close();
}
debug.Text = "end";
}
}
A few questions:
Why are they not executing?
In classic ASP for inserts, updates and deletes I would use con.Execute(query) as supposed to using a recordset, am I running my update statement correctly here?
Is my design of the queries good, or should I be executing them in a different manner?
The reason it's not doing anything is because you're not actually executing the queries. What you need to do is:
// Verify that username is unique
using (SqlCommand cmd = new SqlCommand("UPDATE tblSiteSettings SET isActive = 0", cn))
{
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
using (SqlCommand cmd = new SqlCommand("INSERT INTO tblSiteSettings (allowProductRatings, allowComments, siteName, settingDate, isActive) VALUES (#allowRatings, #allowcomments, #siteName, getDate(), 1)", cn))
{
cmd.Parameters.Add("#allowRatings", SqlDbType.Bit).Value = 1;
cmd.Parameters.Add("#allowcomments", SqlDbType.Bit).Value = 1;
cmd.Parameters.Add("#siteName", SqlDbType.VarChar, 128).Value = "lol";
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
It's the line cmd.ExecuteNoneQuery(); that you're missing. There are various different Execute methods exposed by the SqlCommand class, the most commonly used are:
ExecuteNonQuery: Executes a query and returns no result from the query (it does return the rows affected as its return value however)
ExecuteScalar: Executes a query and returns the value in the first column of the first row
ExecuteReader: Executes a query and returns the data to a SqlDataReader
Your are missing
cmd.ExecuteScalar();
You may also reuse you SqlConnection, you can open the connection right after the using (SqlConnection cn = new Sql... statement. You don't have to close the connection when the SqlConnection is in a using block, accordning to the documentation the connection is closed when you are leaving the using block.

Categories

Resources