i recieve this message when i run the action: "There is already an open DataReader associated with this Command which must be closed first."
my code is:public void UpdatePoints(string rightScore, string rightWinner)
{
cmd.CommandText = "select * from Users_Details";
cmd.Connection = connection;
connection.Open();
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
int points=0;
string sql;
string hisScore = (string)rdr["lastbetscore"];
string hisWinner = (string)rdr["lastbetwinner"];
if (rightScore == hisScore)
points = points + 30;
if (rightWinner == hisWinner)
{
points = points + 20;
}
sql = "update Users_Details set lastgame_points='" + points + "', gamesplayed='" + ((int)rdr["gamesplayed"] + 1) + "',currentpoints='" + ((int)rdr["currentpoints"] + points) + "',pointsPG='" + (((int)rdr["currentpoints"] + points) / ((int)rdr["gamesplayed"] + 1)) + "' where username='" + (string)rdr["username"] + "'";
cmd.CommandText = sql;
cmd.ExecuteScalar();
}
rdr.Close();
connection.Close();
}
The error message is pretty specific about what you doing wrong. You cannot reuse the command or the connection for another command while you're reading data from it. You must firstly read all the data to some List or another data structure and then update db with each element of this List.
Also, consider to execute your statements in transaction
var transaction = connection.BeginTransaction();
...
transaction.Commit();
This will speed up your updates since transaction will be created and commited only once but other way transaction will be created implicitely on each update
You should create a new Command instance instead of reusing the old one here:
sql = "update Users_Details set lastgame_points='" + points + "', gamesplayed='" + ((int)rdr["gamesplayed"] + 1) + "',currentpoints='" + ((int)rdr["currentpoints"] + points) + "',pointsPG='" + (((int)rdr["currentpoints"] + points) / ((int)rdr["gamesplayed"] + 1)) + "' where username='" + (string)rdr["username"] + "'";
cmd.CommandText = sql;
cmd.ExecuteScalar();
In addition, read up on command parameters, formatting the sql string yourself opens you up to SQL injection attacks.
Related
This question already has answers here:
how to get the last record number after inserting record to database in access
(6 answers)
Closed 1 year ago.
Am working with Access as Database in C# (Visual Studio 15). I want to save form entries (add record) into the Access Database and would want the corresponding ID of the record to show in MsgBox upon a successful saving. I have tried the following:
private void Form21_Load(object sender, EventArgs e)
{
try
{
connection.Open();
checkConnection.Text = "Server Connection, Successful";
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error, Server not connected " + ex);
}
}
private void Button6_Click(object sender, EventArgs e)
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
command.CommandText = "insert into Students_File ([YourNames],[Nationality],[StateOfOrigin],[PlaceOfBirth],[DoB],[HomeAddress],[LastSchools1],[LastClass1],[LastSchools2],[LastClass2],[LastSchools3],[LastClass3],[AdmClass],[CurrentClass],[Guidian],[GuardianContact],[UserName],[PassWord],[Gender],[RegistrationDate]) values('" + YourNames.Text + "','" + Nationality.Text + "','" + StateOfOrigin.Text + "','" + PlaceOfBirth.Text + "','" + DoB.Text + "','" + HomeAddress.Text + "','" + LastSchools1.Text + "','" + LastClass1.Text + "','" + LastSchools2.Text + "','" + LastClass2.Text + "','" + LastSchools3.Text + "','" + LastClass3.Text + "','" + AdmClass.Text + "','" + CurrentClass.Text + "','" + Guidian.Text + "','" + GuardianContact.Text + "','" + UserName.Text + "','" + PassWord.Text + "','" + Gender.Text + "','" + RegistrationDate.Text + "')";
command.ExecuteNonQuery();
//MessageBox.Show("Congrats! Your registration, is successful. You may now click close button, then proceed to login");
command.CommandText = "Select * from Students_File where UserName='" + UserName.Text + "' and PassWord='" + PassWord.Text + "'";
OleDbDataReader reader = command.ExecuteReader();
int count = 0;
while (reader.Read())
{
count = count + 1;
}
if (count == 1)
{
MessageBox.Show("Congrats! Your registration, is successful. You may now click close button, then proceed to login");
this.Close();
}
else if (count > 1)
{
MessageBox.Show("Sorry, the chosen username or password is currently existing or picked by another user. Consequently, your registration was not successful. Do please, decide another but a unique one. Thank you");
}
connection.Close();
}
You can do it this way:
using (OleDbCommand Command = new OleDbCommand("", conn))
{
Command.CommandText = "Your big ugly mess - need to change this to parmaters!)";
Command.Connection.Open();
Command.ExecuteNonQuery();
Command.CommandText = "Select ##Identity";
var intLastID = Command.ExecuteScalar;
MsgBox("Last id into database = " + intLastID);
}
As noted, you do want to change that insert command - it too long, too difficult to maintain, and subject to mistakes in code and even sql injection.
But, for now, you can use the above approach to get/pick up the last ID insert.
In solution to my inquiry, i have the following code (From Kevin):
string query = "Insert Into Categories (CategoryName) Values (?)";
string query2 = "Select ##Identity";
int ID;
string connect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb";
using (OleDbConnection conn = new OleDbConnection(connect))
{
using (OleDbCommand cmd = new OleDbCommand(query, conn))
{
cmd.Parameters.AddWithValue("#CategoryName", OleDbType.Integer);
conn.Open();
cmd.ExecuteNonQuery();
cmd.CommandText = query2;
ID = (int)cmd.ExecuteScalar();
}
}
Now, my challenge is how do i get the ID to appear in messagebox after a successful record creation. Please consider my earliest code in this post in connection with this.
Actually I want to make the button click and execute those 2 queries in one-time manner.
string Query = "UPDATE harga_semasa SET we_buy='" + this.textBox1.Text + "',we_sell='" + this.textBox2.Text + "', idharga_semasa='" + this.label5.Text + "' WHERE type='" + this.label1.Text + "';";
string Query2 = "UPDATE harga_semasa SET we_buy='" + this.textBox3.Text + "',we_sell='" + this.textBox4.Text + "', idharga_semasa='" + this.label10.Text + "' WHERE type='" + this.label4.Text + "';";
MySqlConnection MyConn2 = new MySqlConnection(ConString);
MySqlCommand MyCommand2 = new MySqlCommand(Query2, MyConn2);
MySqlCommand MyCommand1 = new MySqlCommand(Query, MyConn2);
MySqlDataReader MyReader2;
MyConn2.Open();
MyReader2 = MyCommand2.ExecuteReader();
MyReader2 = MyCommand1.ExecuteReader();
MessageBox.Show("Data Updated");
while (MyReader2.Read())
{
}
MyConn2.Close();
How do I execute multiple with this code? I try to add some data to the existing table which is already inserted. I am newbie in C# and start to understand some of the code.
You cannot reuse the same connection with multiple MySqlDataReader objects simultaneously: https://mysqlconnector.net/troubleshooting/connection-reuse/
Since your code doesn't actually need the MySqlDataReader, a simple fix is to use ExecuteNonQuery to execute your UPDATE statements.
You should also use parameterised queries to avoid SQL injection and using statements to close the connection automatically
using (var connection = new MySqlConnection(ConString))
{
connection.Open();
using (var command = new MySqlCommand(#"UPDATE harga_semasa SET we_buy=#we_buy, we_sell=#we_sell, idharga_semasa=#idharga_semasa WHERE type=#type;", connection)
{
command.Parameters.AddWithValue("#we_buy", this.textBox1.Text);
command.Parameters.AddWithValue("#we_sell", this.textBox2.Text);
command.Parameters.AddWithValue("#idharga_semasa ", this.label5.Text);
command.Parameters.AddWithValue("#type", this.label1.Text);
// use this to run the query (without MySqlDataReader)
command.ExecuteNonQuery();
}
// execute your second query the same way here
MessageBox.Show("Data Updated");
}
I am getting an exception called There is already an open Data Reader Associated with this command which must be closed first, I tried to look up solution on Google I tried using MARS=true in connection string and also kept everything inside USING but it didn't solved the problem.
i get an Exception in line
cm.ExecuteNonQuery();
public void UpdateActionSchedule(string actionScheduleKey, string note, string PEOPLE_CODE_ID)
{
using (SqlConnection con = new SqlConnection("server=123; database=abc; user id=qwe; password=qwe;"))
{
con.Open();
if (note == "" || note == null)
{
string UPDATE_COMPLETE = String.Format("UPDATE ACTIONSCHEDULE SET EXECUTION_DATE = '" + DateTime.Now + "', COMPLETED = 'Y', REVISION_OPID='WFLOW' where UNIQUE_KEY = '" + actionScheduleKey + "' and people_org_code_id='" + PEOPLE_CODE_ID + "'");
SqlCommand cd = new SqlCommand(UPDATE_COMPLETE, con);
cd.ExecuteNonQuery();
cd.Dispose();
}
else
{
string oriNote = "";
string GET_NOTE = String.Format("SELECT NOTE FROM ACTIONSCHEDULE WHERE people_org_code_id='{0}' and UNIQUE_KEY='{1}'", PEOPLE_CODE_ID, actionScheduleKey);
using (SqlCommand cmd = new SqlCommand(GET_NOTE, con))
{
// SqlDataReader dr = cmd.ExecuteReader();
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
oriNote = dr["NOTE"].ToString();
}
note = oriNote + " " + note;
}
//string UPDATE = String.Format("UPDATE ACTIONSCHEDULE SET Note = '" + note + "' where UNIQUE_KEY = '" + actionScheduleKey + "' and people_org_code_id='" + PEOPLE_CODE_ID + "'");
//SqlCommand cm = new SqlCommand(UPDATE, con);
//cm.ExecuteNonQuery();
//cm.Dispose();
string UPDATE_COMPLETE = String.Format("UPDATE ACTIONSCHEDULE SET EXECUTION_DATE = '" + DateTime.Now + "',Note = '" + note + "', COMPLETED = 'Y', REVISION_OPID='WFLOW' where UNIQUE_KEY = '" + actionScheduleKey + "' and people_org_code_id='" + PEOPLE_CODE_ID + "'");
SqlCommand cmw = new SqlCommand(UPDATE_COMPLETE, con);
cmw.ExecuteNonQuery();
cmw.Dispose();
}
}
}
}
}
In the second half of the code, you have a loop over cmd / dr, and inside that loop, you use cmw with ExecuteNonQuery. That means you're trying to execute two commands at once. Since you've already completed the loop: just move that code outside the using on the dr.
However, it looks like you could also do all of this in a single round trip with better SQL.
i'm trying to lock the table som other client can't change in it until i'm done but its not working. i have create 2 projekt, both is exactly the same. i start those project at a same time. when i chose the table it should lock that table but the other projekt still can get the table and make change. here is the code i have done.
SqlConnection con = new SqlConnection(ConStr);
con.Open();
SqlCommand _Command = new SqlCommand("SELECT * FROM " + table + " WITH (TABLOCK,HOLDLOCK)", con);
_Command.CommandType = CommandType.Text;
_Command = con.CreateCommand();
SqlTransaction _Transaction = con.BeginTransaction(IsolationLevel.Serializable);
_Command.Connection = con;
_Command.Transaction = _Transaction ;
public void Commit()
{
_Command.CommandText = "UPDATE " + table + " SET " + column[1] + " = '" +
txtBox1.Text + "', " + column[2] + " = '" +
txtBox2.Text + "', " + column[3] + " = '" +
txtBox3.Text + "', " + column[4] + " = '" +
txtBox4.Text + "' WHERE " + column[0] + " = " + txtBox0.Text;
_Command.ExecuteNonQuery();
if (_Transaction != null)
{
_Transaction .Commit();
}
}
public void commit is for later on when i'm done with the change.
thanks in advance
This is the modern syntax for what you're attempting. Also, according to the documentation, you shouldn't require table hints with IsolationLevel.Serializable. To maintain your lock, you need to create your transaction before selecting from the first query.
When using TransactionScopes, the framework will automatically enroll connections in open transactions and automatically rollback if scope.Complete() hasn't been called. I.e. An error occurred or you skipped scope.Complete() because of some failed verification.
https://msdn.microsoft.com/en-us/library/system.data.isolationlevel%28v=vs.110%29.aspx
var options = new TransactionOptions();
options.IsolationLevel = IsolationLevel.Serializable;
using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
{
var something = ReadSomething();
WriteSomething(something);
scope.Complete();
}
Try use TABLOCKX :
SELECT * FROM table (TABLOCKX)
The above command will queue other reads and updates outside your transaction until the transaction commite or rolled back
I have a form in windows where I am doing insert statement for header and detail.
I am using MySqlTransaction for the form. When there is no error in header and detail the transaction gets committed but when there is an error in insert query of detail then the following error comes while rollback
There is already an open DataReader associated with this Connection
which must be closed first.
Here is my code.
public string Insert_Hardening_Measures_HdrANDDtl(BL_Vessel_Hardening_Measures objHdr, List<BL_Vessel_Hardening_Measures> objDtl)
{
string success = "true";
string success1 = "";
MySqlConnection MySqlConnection1 = new MySqlConnection(strCon);
MySqlConnection1.Open();
MySqlTransaction MyTransaction = MySqlConnection1.BeginTransaction();
MySqlCommand MyCommand = new MySqlCommand();
MyCommand.Transaction = MyTransaction;
MyCommand.Connection = MySqlConnection1;
try
{
MyCommand.CommandText = "insert into hardening_measures_hdr (Hardening_Measures_Hdr_id,Month,Year) values (" + objHdr.Hardening_Measures_Hdr_id + ",'" + objHdr.Month + "','" + objHdr.Year + "')";
MyCommand.ExecuteNonQuery();
for (int i = 0; i < objDtl.Count; i++)
{
MyCommand.CommandText = "insert into hardening_measures_dtl (Hardening_Measures_Dtl_id,Hardening_Measures_Hdr_id,Hardening_Measures_Mst_id,Value) values (" + objDtl[i].Hardening_Measures_Dtl_id + "," + objDtl[i].Hardening_Measures_Hdr_id + ",'" + objDtl[i].Hardening_Measures_Mst_id + ",'" + objDtl[i].Value + "')";
MyCommand.ExecuteNonQuery();
}
MyTransaction.Commit();
MySqlConnection1.Close();
}
catch
{
MyTransaction.Rollback();
}
return success;
}
Anybody who have come through this kind of problem please suggest something