I am trying to make an update on my MySql database, but I don't understand why it doesn't work when executing from MySqlCommand, I have the famous message "check the manual that corresponds to your MySQL server version" (I already have hundreds of queries working correctly, so I guess something is with syntax?).
edit 2 : Here is the part "near " :
'В-513',PRIORITY=1050,QUANTITY_INIT=28,QUANTITY_REMAINING=0,FICHIER='C:\\Actcut3' at line 1'
Here is the update query :
UPDATE launching_order_details SET
ID_LO=1935,
ID_CONTRACT=4228,
ID_PHASE=11765,
ID_ASS=235314,
LIST_REP_ORI='1005817//В-513//235314//В1007//11765//1//30',IS_SUBDETAIL=0,
REF_DETAIL='3201\\1\\В1007\\В-513\\',
NAME='В-513',
PRIORITY=1050,QUANTITY_INIT=28,QUANTITY_REMAINING=0,
FICHIER='C:\\Actcut3.10\\Data\\Parts\\3201\\1\\В1007\\В-513.ini' WHERE ID=27701
Of course I send it in a same line, I just splitted it here for better readability.
If I make a copy/paste of query, then execute it from phpMyadmin, all is working fine.
Edit : C# code :
DBConnect class :
public void Update(string query)
{
if (this.OpenConnection() == true)
{
if (isMySQL)
{
MySqlCommand cmd = new MySqlCommand(query.Replace("[vsteel].", ""), connection);
cmd.ExecuteNonQuery();
this.CloseConnection();
}
else
{
SqlCommand command = new SqlCommand(query, MSconnection);
command.Parameters.Add(new SqlParameter("0", 1));
//command.Connection = this.MSconnection;
command.ExecuteNonQuery();
this.CloseConnection();
}
}
}
public bool OpenConnection()
{
if (isMySQL)
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{
//When handling errors, you can your application's response based
//on the error number.
//The two most common error numbers when connecting are as follows:
//0: Cannot connect to server.
//1045: Invalid user name and/or password.
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server. Contact administrator");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
System.Windows.Forms.Application.Exit();
Global.is_restarted = true;
return false;
}
}
else
{
try
{
MSconnection.Open();
return true;
}
catch (MySqlException ex)
{
//When handling errors, you can your application's response based
//on the error number.
//The two most common error numbers when connecting are as follows:
//0: Cannot connect to server.
//1045: Invalid user name and/or password.
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server. Contact administrator");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
System.Windows.Forms.Application.Exit();
Global.is_restarted = true;
return false;
}
}
}
RepereLO class :
private void update()
{
this.listRepereOri = this.listRepereOri.OrderBy(x => x.Priority).ThenBy(x => x.ID).ToList();
DBConnect DataBase = new DBConnect();
string query = "UPDATE [vsteel].launching_order_details SET " +
"ID_LO=" + this.launchingOrder.ID + "," +
"ID_CONTRACT=" + this.contract.ID + "," +
"ID_PHASE=" + this.phase.ID + "," +
"ID_ASS=" + this.assembly.ID + "," +
"LIST_REP_ORI=\'" + convertListRepereOriToString() + "\'," +
"IS_SUBDETAIL=" + Convert.ToInt32(this.isSubRepere) + "," +
"REF_DETAIL=\'" + this.refDetail + "\'," +
"NAME=\'" + this.name + "\'," +
"PRIORITY=" + this.priority + "," +
"QUANTITY_INIT=" + this.quantity + "," +
"QUANTITY_REMAINING=" + this.remainingQuantity + "," +
"FICHIER=\'" + Global.ReplaceSpecialCharacters(this.fileName) + "\' " +
"WHERE ID=" + this.id;
DataBase.Update(query);
}
EDIT 2 : Parametirezed query
my DBConnect class
public void UpdateNew(string query, MySqlParameter[] myParamArray)
{
if (this.OpenConnection() == true)
{
using (MySqlCommand cmd = new MySqlCommand(query.Replace("[vsteel].", ""), connection))
{
for (int i = 0; i < myParamArray.Count(); i++)
{
cmd.Parameters.Add(myParamArray[i]);
}
cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
}
In object :
private void update()
{
this.listRepereOri = this.listRepereOri.OrderBy(x => x.Priority).ThenBy(x => x.ID).ToList();
string query = "UPDATE [vsteel].launching_order_details SET " +
"ID_LO=#idLo," +
"ID_CONTRACT=#idContract," +
"ID_PHASE=#idPhase," +
"ID_ASS=#idAss," +
"LIST_REP_ORI=#listRepOri," +
"IS_SUBDETAIL=#isSubdetail," +
"REF_DETAIL=#refDetail," +
"NAME=#name," +
"PRIORITY=#priority," +
"QUANTITY_INIT=#qtyInit," +
"QUANTITY_REMAINING=#qtyRemaining," +
"FICHIER=#fichier" +
" WHERE ID=#id";
MySqlParameter[] listParams = new MySqlParameter[]
{
new MySqlParameter("id", this.id),
new MySqlParameter("idLo", this.launchingOrder.ID),
new MySqlParameter("idContract", this.Contract.ID),
new MySqlParameter("idPhase", this.Phase.ID),
new MySqlParameter("idAss", this.Assembly.ID),
new MySqlParameter("listRepOri", this.convertListRepereOriToString()),
new MySqlParameter("isSubdetail", this.isSubRepere),
new MySqlParameter("refDetail", this.refDetail),
new MySqlParameter("name", this.name),
new MySqlParameter("priority", this.priority),
new MySqlParameter("qtyInit", this.quantity),
new MySqlParameter("qtyRemaining", this.remainingQuantity),
new MySqlParameter("fichier", this.fileName),
};
DBConnect DataBase = new DBConnect();
DataBase.UpdateNew(query, listParams);
}
The actual problem is using string concatenation to construct a query from external input. This leaves the code wide open to SQL injection, conversion errors (what date format? decimal separator?) and ... syntax errors like this. What if Name is O'Reily for example? Or a user entered ' DROP TABLE Students; # ? No amount of escaping or replacing is going to fix the real bug - using string concatenation.
The correct way to do this is to use parameterized queries. This is actually easier than concatenating strings. If you use a library like Dapper, it's as easy as :
string sql=#"UPDATE [vsteel].launching_order_details
SET
ID_LO=#idlo,
ID_CONTRACT=#contract,
ID_PHASE=#phase,
ID_ASS=#assembly,
LIST_REP_ORI=#ori,
IS_SUBDETAIL=#isSubDetail,
REF_DETAIL=#ref,
NAME=#name,
PRIORITY=#priority,
QUANTITY_INIT=#initial,
QUANTITY_REMAINING=#remaining,
FICHIER=#path,
WHERE ID=#id";
using(var connection=new MySqlConnection(...))
{
connection.Execute(sql, new {
id,
idLo=launchingOrder.ID ,
contract=contract.ID,
....,
path=fileName});
}
Without Dapper, the code is a bit more complex but still easier and safer to write than string concatenation and trying to replace characters.
using(var connection=new MySqlConnection)
using (var cmd=new MySqlCommand(query,connection))
{
cmd.Parameters.AddWithValue("#id",this.id);
...
connection.Open();
cmd.ExecuteNonQuery();
}
BTW the DbConnect class has other issues as well. Long-lived database connections are a bug that harms performance and scalability. The locks taken during a connection remain active until it closes, which results in increased blocking for all clients. This happens even in databases with multi-version concurrency like PostgreSQL.
Connections are meant to be opened as late as possible and closed immediately after use. That's why you see all samples and tutorials create connections in a using block. This ensures the connection is close immediately after use.
ADO.NET uses connection pooling to eliminate the cost of opening a new connection, by reseting existing connections. When DbConnection.Close is called, the connection is reset and placed in a connection pool.
Tutorials
Basics of ADO.NET is a short intro to ADO.NET that explains what the various classes do and how they're used.
MySQL's Tutorial: An Introduction to Connector/NET Programming shows how to use ADO.NET with MySQL.
Microsoft's documentation on ADO.NET is almost an entire book that goes in great depth, so you should probably use it only as a reference
Dapper is a micro-ORM library that makes it very easy to map object properties to parameters and results to objects. It can be used with any ADO.NET provider, including MySQL.
With Dapper, one can write code like this :
public class Dog
{
public int? Age { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public float? Weight { get; set; }
public int IgnoredProperty { get { return 1; } }
}
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = #Age, Id = #Id", new { Age = (int?)null, Id = guid });
And the library will map the Age and Id properties to #Age and #Id. It will also map the Age and Id columns in the results to Dog.Age and Dog.Id
Related
I try to update a row in my Access, my code is running fine and I have to Exception, But is nothing change un my database
This is my method it calls from a form in a Winform project
public static void UpdateNextReportNumber(int machineNumber, string reportNumber)
{
try
{
using (OleDbConnection openCon = new OleDbConnection(localConnectionString))
{
string saveStaff = "UPDATE [Calibration] " +
"SET [NextReportNumber]=#report " +
"where [MachineNumber]=#machine";
using (OleDbCommand querySaveStaff = new OleDbCommand(saveStaff))
{
querySaveStaff.Connection = openCon;
querySaveStaff.Parameters.AddWithValue("#machine", 16);
querySaveStaff.Parameters.AddWithValue("#report",2);//Convert.ToInt32(reportNumber.Remove(0, 3)) + 1
openCon.Open();
int recordsAffected = querySaveStaff.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
//WriteLog(ex.StackTrace, ex.Message);
throw ex;
}
}
this is how my Calibration table looks like
my code pass this line
int recordsAffected = querySaveStaff.ExecuteNonQuery();
But in recordsAffected I have value 0
I have no idea what to do
I tried to execute using Access this query
UPDATE [Calibration]
SET [NextReportNumber]=2
where [MachineNumber]=36
And its work fine
I also used
public static void AddCalibration(Calibration calibration)
{
try
{
using (OleDbConnection openCon = new OleDbConnection(localConnectionString))
{
string saveStaff = "INSERT into [Calibration] ([MachineNumber] ,[LastCalibrationDate] ,[NextCalibrationDate])" +
"VALUES (#MachineNumber, #LastCalibrationDate, #NextCalibrationDate)";
using (OleDbCommand querySaveStaff = new OleDbCommand(saveStaff))
{
querySaveStaff.Connection = openCon;
querySaveStaff.Parameters.AddWithValue("#MachineNumber", calibration.MachineNumber);
querySaveStaff.Parameters.AddWithValue("#LastCalibrationDate", calibration.LastCalibrationDate);
querySaveStaff.Parameters.AddWithValue("#NextCalibrationDate", calibration.NextCalibrationDate);
openCon.Open();
int recordsAffected = querySaveStaff.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
//WriteLog(ex.StackTrace, ex.Message);
throw ex;
}
}
And it works fine also...
Thanks for help...
In OleDb parameters are not recognized by their name but by their position in the parameters collection. You should simply change the line order of your parameters
querySaveStaff.Parameters.AddWithValue("#report",2);
querySaveStaff.Parameters.AddWithValue("#machine", 16);
In your current query the report's parameter is used in the Where statement not in the update part and of course nothing is updated because there is no record with WHERE MachineNumber = 2
Indeed, in OleDb you usually specify the parameters placeholder with a single ? not with the #something syntax, but Access, probably for easier portability with Sql Server accepts also the # syntax, still the positions in parameter's collection should be the correct one expected in the query text.
I have a database with the following tables:
**Camping Spot**
PK - id - int
FK - location_id - int
number - int
capacity - int
**Location**
PK - id - int
name - string
street - varchar
etc.
**Event**
PK - id - int
FK - location_id - int
name - string
datestart - datetime
etc.
I have the following classes
namespace modellen
{
public class Spot
{
public int Id { get; set; }
public int Number { get; set; }
public int Capacity { get; set; }
}
}
and
namespace DAL_laag
{
public class SpotDal
{
List<Spot> spots = new List<Spot>();
private Database database = new Database();
public GiveAvailiableSpots(int event_id)
{
string query = "A query that gets Id, Number and Capacity";
return ?
}
}
I want to get the id, number and capacity values from the table with a mssql query. Then I want to create a new Spot object and add the object to my list of Spots.
I can't figure out what the query would be to get these three value and the code to create a new object with these three values.
How would I do this?
I think your query needs to look something like this.
string query = #"select id,
number,
capacity
from tblCampingSport cs
left join tblLocation l on cs.location_id == l.id
left join tblEvent e on e.location_id = l.id
where e.id = #eventId";
You're call to the db will look something like this:
List<QueryResult> results = new List<QueryResult>();
using(SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
using(SqlCommand cmd = new SqlCommand(query, conn)
{
cmd.Parameters.AddWithValue("#eventId", event_id);
var reader = cmd.ExecuteReader();
if(reader.HasRows())
{
while(reader.Read())
{
QueryResult result = new QueryResult();
result.EventId = (int)reader["id"];
result.Number = (int)reader["number"];
result.Capacity = (int)reader["capacity"];
results.Add(result);
}
}
}
}
Your class to store the results:
class QueryResult
{
int EventId { get; set;}
int Number { get; set;}
int Capacity { get; set;}
}
None of this is tested or even compiled (it was written straight into this textbox), but I think it's a rough outline of how to get what you want from your tables.
Assuming you are using the MySql Libary to connect to your database. You need a class that allows you to connect to the database which looks like the code segment below; I am using the UWP for Windows 10 with c# so the code should work, however, there may be slight changes but nothing major.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using Windows.UI.Popups;
using Walsall_College_Auditor.Classes;
namespace Walsall_College_Auditor.Models
{
class dbConnect
{
private MySqlConnection connection;
private string server;
private string database;
private string uid;
private string password;
//Constructor
public dbConnect()
{
Initialize();
}
//Initialize values
private void Initialize()
{
//Prevent the application from throwing "windows-1252' is not a supported encoding name."
System.Text.EncodingProvider ppp;
ppp = System.Text.CodePagesEncodingProvider.Instance;
Encoding.RegisterProvider(ppp);
server = "localhost";
database = "your_db_name"; //Put the new database name here
uid = "root"; //Your db Login/Username
password = ""; //Your db login password
string connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";"
+ "UID=" + uid + ";" + "PASSWORD=" + password + ";SslMode=None";
connection = new MySqlConnection(connectionString);
}
//open connection to database
private bool OpenConnection()
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{
//When handling errors, you can your application's response based
//on the error number.
//The two most common error numbers when connecting are as follows:
//0: Cannot connect to the server.
//1045: Invalid username and/or password.
switch (ex.Number)
{
case 0:
var dialog1 = new MessageDialog("Cannot connect to server. Contact administrator");
dialog1.Title = "Connection Error";
dialog1.ShowAsync();
break;
case 1045:
var dialog2 = new MessageDialog("Invalid username/password, please try again");
dialog2.Title = "Connection Error";
dialog2.ShowAsync();
break;
}
return false;
}
}
//Close connection
private bool CloseConnection()
{
try
{
connection.Close();
return true;
}
catch (MySqlException ex)
{
var dialog = new MessageDialog(ex.Message);
dialog.Title = "Disconnecting Error";
dialog.ShowAsync();
return false;
}
}
There are other methods that I can post if you require them. Personally, I used this Connect c# to MySql to help me develop my methods for querying the database. If you are using windows forms then this will be perfect and if you are using the Universal Windows Platform then you will require a different version of the DLL file and adjustments to your code that are not shown on the provided link.
However to answer your question correctly: The code below exists in the same DB class and the code is a function that returns a list of companies.
public List<company> getSots()
{
string query = "SELECT * FROM tbl_spot"; //Your table name here
List<Spot> dbSpots = new List<Spot>(); //List to store the gathered spots
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
//Create a new company object and populate with a row at a time
Spot x = new Spot();
x.Id = int.Parse(dataReader["id_spot"].ToString());
x.Number = int.Parse(dataReader["number"].ToString());
x.Capacity = int.Parse(dataReader["capacity"].ToString());
dbSpots.Add(x); //Add created Spot to the Spots list
}
dataReader.Close();
this.CloseConnection();
return dbCmpys; //Return the gathered db companies
}
else { return dbCmpys; }
}
As you can see the code creates a list of the object type (in your case Spot), populates it using a loop to cycle through all the database records and returns the list once completed.
To use the function: In another class or form, create a new instance of the DB class, create a list that equals the function; like so:
//Your form code/class
class SpotForm
{
private dbConnect dbConnection = new dbConnect(); //Database connection
private List<Spot> listSpots = new List<Spot>(); //Local list
// Constructor
public SpotForm()
{
listSpots = dbConnection.getSpots();
}
You now will have a list of the Spots from the database to do with as you please such as looping through to gather or manipulate the data.
Well i had a weird exception on my program so i tried to replicate it to show you guys, so what i did was to create a table with id(int-11 primary), title(varchar-255) and generated 100k random titles with 40 chars lenght, when i run my method that reads the count for each id it throws an exception check below for more.
What i found is that this was because of timeouts so i tried this for the timeouts.
set net_write_timeout=99999; set net_read_timeout=99999;
Tried pooling=true on connection
Tried cmd.timeout = 120;
I also tried adding MaxDegreeOfParallelism i played with multiple values but still the same error appears after a while.
My exception:
Could not kill query, aborting connection. Exception was Unable to
read data from the transport connection: A connection attempt failed
because the connected party did not properly respond after a period of
time, or established connection failed because connected host has
failed to respond.
public static string db_main = "Server=" + server + ";Port=" + port + ";Database=" + database_main + ";Uid=" + user + ";Pwd=" + password + ";Pooling=true;";
private void button19_Click(object sender, EventArgs e)
{
List<string> list = db.read_string_list("SELECT id from tablename", db.db_main);
//new ParallelOptions { MaxDegreeOfParallelism = 3 },
Task.Factory.StartNew(() =>
{
Parallel.ForEach(list, id =>
{
string sql = "SELECT COUNT(*) FROM tablename where id=" + id;
var ti = db.read_int(sql, db.db_main);
Console.WriteLine(ti);
});
}).ContinueWith(_ =>
{
Console.WriteLine("Finished");
});
}
public static int? read_int(string sql, string sconn)
{
var rdr = MySqlHelper.ExecuteReader(db.db_main, sql);
if (rdr.HasRows)
{
rdr.Read();
return rdr.GetInt32(0);
}
else
return null;
}
Alternate Method to read int with timeout option.
public static int? read_int2(string sql, string sconn)
{
using (var conn = new MySqlConnection(sconn))
{
using (var cmd = new MySqlCommand(sql, conn))
{
//cmd.CommandTimeout = 120;
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
rdr.Read();
return rdr.GetInt32(0);
}
else
return null;
}
}
}
}
What can be causing this? any clues?
So finally my solution on this was to increase net_read_timeout variable (im pointing out net_write_timeout because that can happen when executing a long query too)
Run these queries *Note: After you restart your PC default values will take place again.
set ##global.net_read_timeout = 999;
set ##global.net_write_timeout = 999;
or you can add this on the connection string
default command timeout=999;
Finally i used this method to read the values.
public static int? read_int(string sql, string sconn)
{
try
{
using (MySqlDataReader reader = MySqlHelper.ExecuteReader(sconn, sql))
{
if (reader.HasRows)
{
reader.Read();
return reader.GetInt32(0);
}
else
return null;
}
}
catch (MySqlException ex)
{
//Do your stuff here
throw ex;
}
}
I've developed an emulation program for a game. The program works with MySQL for database communication. I have tried to use the IDisposable method (which is suggested mostly by everyone), to allocate a MySQL connection to a thread, when that specific thread requires something to do with the database. However, when the server reaches over 400 users, the MySQL server gets overloaded with requests. I have also tried the pooling option (size: min 0, max. 150) - it resulted the same issue.
Currently, I am using locking to provide a parallelism system. The system works with static objects (static connection object) to manage the whole server (I think it affects the performance offered by multithreading though).
public static Boolean Query(ref MySqlDataReader Resource, String Query)
{
lock (Connection)
{
MySqlCommand Cmd = new MySqlCommand(Query, Connection);
try
{
Resource = Cmd.ExecuteReader();
}
catch (MySqlException Exception)
{
Console.WriteLine("MySQL Error: " + Exception.Message);
return false;
}
return true;
}
}
A method that works with the "Query" method.
public static String GetObjectProperty(
String Field, String Identifier,
Boolean Primary = true, String Table = "Accounts")
{
String FieldValue = null;
try
{
lock (GeneralDB.Connection)
{
MySqlDataReader DataReader = null;
if (GeneralDB.Query(
ref DataReader,
"SELECT " + MySqlHelper.EscapeString(Field) +
" FROM " + Table +
" WHERE " + (Primary ? "ID" : "Name") + " = '" +
MySqlHelper.EscapeString(Identifier) + "';") == false)
{
return null;
}
if (DataReader == null) return null;
while (DataReader.Read())
FieldValue = DataReader[0].ToString();
DataReader.Close();
return FieldValue;
}
}
catch (Exception Exception)
{
return FieldValue;
}
}
I desperately need some suggestions. Thanks.
I'm selecting about 20,000 records from the database and then I update them one by one.
I looked for this error and I saw that setting the CommandTimeout will help, but not in my case.
public void Initialize()
{
MySqlConnectionStringBuilder SQLConnect = new MySqlConnectionStringBuilder();
SQLConnect.Server = SQLServer;
SQLConnect.UserID = SQLUser;
SQLConnect.Password = SQLPassword;
SQLConnect.Database = SQLDatabase;
SQLConnect.Port = SQLPort;
SQLConnection = new MySqlConnection(SQLConnect.ToString());
}
public MySqlDataReader SQL_Query(string query)
{
MySqlCommand sql_command;
sql_command = SQLConnection.CreateCommand();
sql_command.CommandTimeout = int.MaxValue;
sql_command.CommandText = query;
MySqlDataReader query_result = sql_command.ExecuteReader();
return query_result;
}
public void SQL_NonQuery(string query)
{
MySqlCommand sql_command;
sql_command = SQLConnection.CreateCommand();
sql_command.CommandTimeout = int.MaxValue;
sql_command.CommandText = query;
sql_command.ExecuteNonQuery();
}
And here is my method which makes the select query:
public void CleanRecords()
{
SQLActions.Initialize();
SQLActions.SQL_Open();
MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`");
while(cashData.Read()){
if(cashData["income_money"].ToString() == cashData["total"].ToString()){
UpdateRecords(cashData["id"].ToString());
}
}
SQLActions.SQL_Close();
}
And here is the method which makes the update:
public void UpdateRecords(string rowID)
{
SQLActions.Initialize();
SQLActions.SQL_Open();
SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id`='" + rowID + "'");
SQLActions.SQL_Close();
}
Changing the database structure is not an option for me.
I thought that setting the timeout to the maxvalue of int will solve my problem, but is looks like this wont work in my case.
Any ideas? :)
EDIT:
The error which I get is "Fatal error encoutered during data read".
UPDATE:
public void CleanRecords()
{
StringBuilder dataForUpdate = new StringBuilder();
string delimiter = "";
SQLActions.Initialize();
SQLActions.SQL_Open();
MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`");
while (cashData.Read())
{
if (cashData["income_money"].ToString() == cashData["total"].ToString())
{
dataForUpdate.Append(delimiter);
dataForUpdate.Append("'" + cashData["id"].ToString() + "'");
delimiter = ",";
}
}
SQLActions.SQL_Close();
UpdateRecords(dataForUpdate.ToString());
}
public void UpdateRecords(string rowID)
{
SQLActions.Initialize();
SQLActions.SQL_Open();
SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id` IN (" + rowID + ")");
SQLActions.SQL_Close();
}
You may be able to use
UPDATE cash_data .... WHERE id IN (SELECT ....)
and do everything in one go. Otherwise, you could do it in two steps: first the select collects all the ids, close the connection and then do the update in obne go with all the ids.
The code for the second option might look something like this:
public void CleanRecords()
{
StringBuilder builder = new StringBuilder();
string delimiter = "";
SQLActions.Initialize();
SQLActions.SQL_Open();
MySqlDataReader cashData = SQLActions.SQL_Query("SELECT `cash`.`id`, SUM(`cash`.`income_money`) AS `income_money`, `cash_data`.`total` FROM `cash_data` JOIN `cash` ON `cash`.`cash_data_id` = `cash_data`.`id` WHERE `user`='0' AND `cash_data`.`paymentterm_id`='0' OR `cash_data`.`paymentterm_id`='1' GROUP BY `cash_data_id`");
while(cashData.Read()){
if(cashData["income_money"].ToString() == cashData["total"].ToString()){
builder.Append(delimiter);
builder.Append("'" + cashData["id"].ToString() + "'");
delimiter = ",";
}
}
SQLActions.SQL_Close();
UpdateRecords(builder.ToString());
}
public void UpdateRecords(string rowIDs)
{
SQLActions.Initialize();
SQLActions.SQL_Open();
SQLActions.SQL_NonQuery("UPDATE `cash_data` SET `end_date`='" + GetMeDate() + "', `user`='1' WHERE `id` IN (" + rowIDs + ")";
SQLActions.SQL_Close();
}
There are multiple problem:
First: You have reading information around 20K using data reader and then doing update one by one in reader itself. Reader holds the connection open until you are finished. So this is not the good way to do it. Solution: We can read the information using Data Adapter.
Second: Rather than doing one by one update, we can update in bulk in one go. There are multiple option for bulk operation. In SQL u can do either by sending information in XML format or u can use Table Valued Parameter (TVP) (http://www.codeproject.com/Articles/22205/ADO-NET-and-OPENXML-to-Perform-Bulk-Database-Opera) OR (http://dev.mysql.com/doc/refman/5.5/en/load-xml.html)