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
I am trying to make an oledb connection to an Access database to insert a new record and retrieving the key generated all at once. The code is this:
private static int createUser(OleDbConnection accessConn)
{
try
{
accessConn.Open();
//DbCommand also implements IDisposable
using (OleDbCommand cmd = accessConn.CreateCommand())
{
//create command with placeholders
cmd.CommandText =
"INSERT INTO EmployeeFiles " +
"([FirstName], [LastName], [JobTitleID], [SecurityLevel], [RowGUID])" +
"VALUES(#FirstName, #LastName, #JobTitleID, #SecurityLevel, #RowGUID)";
//Set Parameters
string FirstName = "Dick";
string LastName = "Tracy";
int JobTitleID = 11;
string SecurityLevel = "1";
string RowGUID = "{" + Guid.NewGuid() + "}";
//add named parameters
cmd.Parameters.AddRange(new OleDbParameter[]
{
new OleDbParameter("#FirstName", FirstName),
new OleDbParameter("#LastName", LastName),
new OleDbParameter("#JobTitleID", JobTitleID),
new OleDbParameter("#SecurityLevel", SecurityLevel),
new OleDbParameter("#RowGUID", RowGUID)
});
int userId = 0;
//Add #EmployeeID to the params collection and then retrieve it with Value
cmd.Parameters.Add("#EmployeeID", OleDbType.Integer).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
userId = (int)cmd.Parameters["#EmployeeID"].Value;
//userId = (int)cmd.ExecuteScalar();
Console.WriteLine("user created successfully: {0}", deliveryId);
return userId;
}
}
catch (Exception ex)
{
Console.WriteLine("Error: Failed creating the user.\n{0}", ex.Message);
return 0;
}
finally
{
accessConn.Close();
}
}
And when I run the code it throws this error:
System.Data.OleDb.OleDbDataAdapter internal error: invalid parameter accessor: 9 BADBINDINFO
I'm pretty sure the problematic line is this:
cmd.Parameters.Add("#EmployeeID", OleDbType.Integer).Direction = ParameterDirection.Output;
And I just don't get where is the mistake.
If I comment that and the next two lines, and uncomment this:
userId = (int)cmd.ExecuteScalar();
It throws the error: Object reference not set to an instance of an object
Is there a way to get this working with OleDbParameter? So far I'm being forced to make the insert and then a select to get the key generated.
I appreciate any suggestion.
I use OleDbDataAdapter and OleDbCommandBuilder to fill DataSet object with database contents, and then update database according to a changes that I made in the DataSet. The problem is that I get the exception: "Concurrency violation: the UpdateCommand affected 0 of the expected 1 records". I've found an explanation of this error:
Because a record could have been modified after it was returned from
the SELECT statement, but before the UPDATE or DELETE statement is
issued, the automatically generated UPDATE or DELETE statement
contains a WHERE clause, specifying that a row is only updated if it
contains all original values and has not been deleted from the data
source. Where an automatically generated update attempts to update a
row that has been deleted or that does not contain the original values
found in the DataSet, the command does not affect any records, and a
DBConcurrencyException is thrown.
That means that auto generated UPDATE command affected 0 rows in the database. I work with paradox(db-file) database and no one changes it except for me. I guess that my program changes the same row two times somewhere. I wanted to debug my program by executing all generated queries manually and finding which one doesn't affect any row(because actually I'm pretty sure that all changes are made only once and the bug is somewhere else))). Is it possible to run auto generated commands manually?
My code is too big and complicated to post it here but generally it works like this(I made a working project and took it from there)
using System;
using System.Data;
using System.Windows.Forms;
using System.Data.OleDb;
namespace OleDBCommandBuilder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string cs = #"Provider=Microsoft.Jet.OLEDB.4.0;";
cs += #"Data Source=C:\FOLDER\1\SPR_KMZ\;";
cs += #"Extended Properties=Paradox 5.x;";
OleDbConnection Connection = new OleDbConnection();
Connection.ConnectionString = cs;
try
{ Connection.Open(); }
catch (Exception ex)
{ MessageBox.Show("Error openning database! " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); }
string SQLQuery = "SELECT * FROM SPR_KMZ WHERE REZ<>0";
DataSet SPR_KMZ = new DataSet();
OleDbDataAdapter DataAdapter = new OleDbDataAdapter();
DataAdapter.SelectCommand = new OleDbCommand(SQLQuery, Connection);
OleDbCommandBuilder builder = new OleDbCommandBuilder(DataAdapter);
try
{
DataAdapter.Fill(SPR_KMZ);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(String.Format("Error \n{0}\n{1}", ex.Message, SQLQuery));
Environment.Exit(0);
}
DataRow[] SPR_KMZ_rows = SPR_KMZ.Tables[0].Select("Fkmz=10000912 AND REZ=1");
foreach (DataRow SPR_KMZ_row in SPR_KMZ_rows)
{
SPR_KMZ_row["DN"] = Convert.ToDateTime("30.12.1899");//26.12.2008
SPR_KMZ_row["Price"] = Convert.ToDouble(0);//168,92
}
DataAdapter.Update(SPR_KMZ);
System.Windows.Forms.MessageBox.Show("Success!");
Environment.Exit(0);
}
}
}
P.S. Previously it updated the database without concurrency exception, but after a lot of changes(I commented out the line "DataAdapter.Update(SPR_KMZ);" for a long time for debugging reason, so I don't know when exactly this error started to throw)
P.S.S. there are no INSERTs or DELETEs in my code, only UPDATEs...
<<UPDATE>>
I've found what was the problem: if "DN" field has NULL value then after changing it, the auto-generated UPDATE Statement don't affect anything, obviously because "DN" is contained in a primary key and command builder didn't expect for primary key field to have NULL values(who ever would))), no surprise this engine is called "Paradox")))
that's why in
CommandBuilder.GetUpdateCommand().CommandText
in where clause for "DN" field there was this kind of pattern:
... WHERE ((REZ = ?) AND (DN = ?) AND ...
while nullable fields are described like this:
... AND ((? = 1 AND Price IS NULL) OR (Price = ?)) AND ((? = 1 AND Nmed IS NULL) OR (Nmed = ?)) AND ...
P.S.S.S. Hey, I can try to set UpdateCommand manually to fix this!)))
Here is how I've managed to set the UpdateCommand manually and even get SQL code for every UPDATE command that is being executed!(more or less)). It is very helpful while debugging - I can see what sql query failed to execute during DataAdapter.Update(DBDataSet) command.
public void Update(DataSet DBDataSet)
{
DataAdapter.RowUpdating += before_update;
DataAdapter.Update(DBDataSet);
}
public void before_update(object sender, EventArgs e)
{
//Convert EventArgs to OleDbRowUpdatingEventArgs to be able to use OleDbCommand property
System.Data.OleDb.OleDbRowUpdatingEventArgs oledb_e = (System.Data.OleDb.OleDbRowUpdatingEventArgs) e;
//Get query template
string cmd_txt = oledb_e.Command.CommandText;
//Modify query template here to fix it
//cmd_txt = cmd_txt.Replace("table_name", "\"table_name\"");
//fill tamplate with values
string cmd_txt_filled = cmd_txt;
foreach(System.Data.OleDb.OleDbParameter par in oledb_e.Command.Parameters)
{
string par_type = par.DbType.ToString();
string string_to_replace_with = "";
if (par.Value.GetType().Name == "DBNull")
{
string_to_replace_with = "NULL";
}
else
{
if (par_type == "Int32")
{
par.Size = 4;
string_to_replace_with=Convert.ToInt32(par.Value).ToString();
}
else if (par_type == "Double")
{
par.Size = 8;
string_to_replace_with=Convert.ToDouble(par.Value).ToString().Replace(",",".");
}
else if (par_type == "DateTime")
{
par.Size = 8;
/* In Paradox SQL queries you can't just specify the date as a string,
* it will result in incompatible types, you have to count the days
* between 30.12.1899 and the required date and specify that number
*/
string_to_replace_with = DateToParadoxDays(Convert.ToDateTime(par.Value).ToString("dd.MM.yyyy"));
}
else if (par_type == "String")
{
string_to_replace_with = '"' + Convert.ToString(par.Value) + '"';
}
else
{
//Break execution if the field has a type that is not handled here
System.Diagnostics.Debugger.Break();
}
}
cmd_txt_filled = ReplaceFirst(cmd_txt_filled, "?", string_to_replace_with);
}
cmd_txt_filled = cmd_txt_filled.Replace("= NULL", "IS NULL");
//Get query text here to test it in Database Manager
//System.Diagnostics.Debug.WriteLine(cmd_txt_filled);
//Uncomment this to apply modified query template
//oledb_e.Command.CommandText = cmd_txt;
//Uncomment this to simply run the prepared update command
//oledb_e.Command.CommandText = cmd_txt_filled;
}
public string ReplaceFirst(string text, string search, string replace)
{
int pos = text.IndexOf(search);
if (pos < 0)
{
return text;
}
return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}
private static string DateToParadoxDays(string date)
{
return (Convert.ToDateTime(date) - Convert.ToDateTime("30.12.1899")).TotalDays.ToString();
}
My Code For Searching Data In SQL Server Compact Database is not working please review my code. any help will be greatly appreciated.
#region btnSearch_Click
private void btnSearch_Click(object sender, EventArgs e)
{
SqlCeConnection con = new SqlCeConnection("Data Source="
+ System.IO.Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "Database.sdf"));
sda = new SqlCeDataAdapter();
if (con.State == ConnectionState.Closed)
{
con.Open();
}
string sql = "select Name from tblCustomers ";
if (tbSearch.Text.Length > 0)
{
sql += "where Name like " + tbSearch.Text + " % ";
}
try
{
SqlCeCommand cmd = new SqlCeCommand(sql, con);
cmd.CommandType = CommandType.Text;
// if you don’t set the result set to
// scrollable HasRows does not work
SqlCeResultSet rs = cmd.ExecuteResultSet(
ResultSetOptions.Scrollable);
if (rs.HasRows)
{
int Name = rs.GetOrdinal("Name");
// Hold the output
StringBuilder output = new StringBuilder();
// Read the first record and get it’s data
rs.ReadFirst();
output.AppendLine(rs.GetString(Name)
+ " " + rs.GetString(Name));
while (rs.Read())
{
output.AppendLine(rs.GetString(Name)
+ " " + rs.GetString(Name));
}
// Set the output in the label
lblResults.Text = output.ToString();
}
else
{
lblResults.Text = "No Rows Found.";
}
}
catch (SqlCeException sqlexception)
{
MessageBox.Show(sqlexception.Message, "Error.",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error.",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
con.Close();
}
#endregion
it's throwing the bellow exception.
There was an error parsing the query. [ Token line number = 1,Token line offset = 53,Token in error = % ]
A useful way to solve such issues is to view the SQL string generated by your code right before sending it to SQL Server. If you can spot the problem immediately, that's great - fix it. If you can't try running the full query directly with the SQL Server Management Studio and see if you understand the problem. If you still can't post this query as a question on a Q&A site (just like here on SO) and it will be much easier to help you.
In this case, it looks to me like you're missing single quotes around the value ("like 'text'") - but I can't be sure cause it depends on the value of tbSearch.Text.
I've written a method which will try and delete a row from a db table based on a primary key id. The problem i have is that the try block is always returning "Success" even if a record has already been deleted / or it doesn't exist.
public string delete_visit(int id)
{
string deleteResponse = null;
string cnn = ConfigurationManager.ConnectionStrings[connname].ConnectionString;
using (SqlConnection connection = new SqlConnection(cnn))
{
string SQL = string.Empty;
SQL = "DELETE FROM [" + dbname + "].[dbo].[" + tbname + "] WHERE VisitorNumber = #IDNumber ";
using (SqlCommand command = new SqlCommand(SQL, connection))
{
command.Parameters.Add("#IDNumber", SqlDbType.Int);
command.Parameters["#IDNumber"].Value = id;
try
{
connection.Open();
command.ExecuteNonQuery();
deleteResponse = "Success";
}
catch (Exception ex)
{
deleteResponse = "There was a problem deleting the visit from the database. Error message: " + ex.Message;
}
}
}
return deleteResponse;
}
I want to be able to tell if the row was affected. I can do this in SQL Server Management Studio like so:
DELETE FROM Visits
WHERE VisitorNumber=88;
IF ##ROWCOUNT = 0
PRINT 'Warning: No rows were updated';
So i want to know how do i plug in the ##ROWCOUNT bit into my c# so that i can tell if the row was deleted?
thanks
ExecuteNonQuery() returns an int, indicating how many rows were affected.
So:
int rowsAffected = command.ExecuteNonQuery();
if (rowsAffected == 0)
{
deleteResponse = "No rows affected";
}
The problem is that this number can be influenced based on what the query actually does. Executing triggers or calling stored procedures could mess with the output, changing the affected number of rows. If you really must, then first execute a query where you check that the record with the given ID exists.