Fatal Error Encountered using LINQ and mysqlconnection - c#

I'm quite new to c# so please any help would be great. I made a simple console code to update to mysql database, rest assured my database is done setting up, App.config is done. Now, the problem is when I run to test my code this error occurred. "Fatal error encountered during command execution"
below is my code:
class library:
public class DBEntity
{
private MySqlConnection DBConnection { get; set; }
public string INSERT = "insert";
public string SELECT = "select";
public string UPDATE = "update";
public void Get_Connection(string ConnectionString)
{
DBConnection = new MySqlConnection(ConnectionString);
}
public void Close_Connection()
{
DBConnection.Close();
}
public void Query(string operation, string query, params object[] values)
{
try
{
DBConnection.Open();
switch (operation)
{
case "update":
try
{
using (MySqlCommand cmd = new MySqlCommand(query, DBConnection))
{
IEnumerable<string> tokens = query.Split(new char[] { ' ', '\'', ';', ',' }).Where(str => str.Contains('#'));
var zipTwoTokens = tokens.Zip(values, (token, vals) => cmd.Parameters.AddWithValue(token, vals)).ToList();
cmd.ExecuteNonQuery();
DBConnection.Close();
}
}
catch (MySqlException e)
{
DBConnection.Close();
Console.WriteLine(e.Message);
}
break;
default:
break;
}
}
catch (MySqlException)
{
}
}
}
The Main class:
class Program
{
static void Main(string[] args)
{
DBEntity database = new DBEntity();
database.Get_Connection(ConfigurationManager.ConnectionStrings["MySQLConnection"].ConnectionString);
database.Query(database.UPDATE, "UPDATE RoyDB.Products SET Products.Name = #productName WHERE Products.ProductID = #product;", "Kayak", 1);
Console.Read();
}
}
Now, the problem is when I run to test my code this error occurred. "Fatal error encountered during command execution"
can anyone help me? I dont seem to get the cause of the error.
any help would be great! Thanks!

The way you split the query up to determine the parameters is not quite correct. In this case it is including the semicolon so you get parameters called #productName and #product;. Add in semicolon to the split string like this:
IEnumerable<string> tokens =
query.Split(new char[] { ' ', '\'', ';'}).Where(str => str.Contains('#'));
Additionally, you need to actually force the Zip method to be called as Linq uses deferred execution. To to this, add ToList on the end of the zip:
var zipTwoTokens =
parameterToken.Zip(values, (prmtoken, vals) =>
cmd.Parameters.AddWithValue(prmtoken, vals)).ToList();

Related

Exception handling quandry

I am throwing a new exception when a database row is not found.
Class that was called:
public ProfileBO retrieveProfileByCode(string profileCode)
{
return retrieveSingleProfile("profile_code", profileCode);
}
private ProfileBO retrieveSingleProfile(string termField, string termValue)
{
ProfileBO profile = new ProfileBO();
//Query string is temporary. Will make this a stored procedure.
string queryString = " SELECT * FROM GamePresenterDB.gp.Profile WHERE " + termField + " = '" + termValue + "'";
using (SqlConnection connection = new SqlConnection(App.getConnectionString()))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
profile = castDataReadertoProfileBO(reader, profile);
}
else
{
// No record was selected. log it and throw the exception (We'll log it later, for now just write to console.)
Console.WriteLine("No record was selected from the database for method retrieveSingleProfile()");
throw new InvalidOperationException("An exception occured. No data was found while trying to retrienve a single profile.");
}
reader.Close();
}
return profile;
}
However, when I catch the exception in the calling class, 'e' is now null. What am I doing wrong? I believe this works fine in Java, so C# must handle this differently.
Calling class:
private void loadActiveProfile()
{
try
{
ProfileBO profile = profileDAO.retrieveProfileByCode(p.activeProfileCode);
txtActiveProfileName.Text = profile.profile_name;
}
catch (InvalidOperationException e)
{
}
}
Now all the code has been put in the question, you can move the try catch outside of your 'loadActiveProfile' method and place it into 'retrieveSingleProfile'.
private void loadActiveProfile()
{
ProfileBO profile = profileDAO.retrieveProfileByCode(p.activeProfileCode);
txtActiveProfileName.Text = profile.profile_name;
}
removed the try catch^
private ProfileBO retrieveSingleProfile(string termField, string termValue)
{
try {
ProfileBO profile = new ProfileBO();
//Query string is temporary. Will make this a stored procedure.
string queryString = " SELECT * FROM GamePresenterDB.gp.Profile WHERE " + termField + " = '" + termValue + "'";
using (SqlConnection connection = new SqlConnection(App.getConnectionString()))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
profile = castDataReadertoProfileBO(reader, profile);
}
else
{
// No record was selected. log it and throw the exception (We'll log it later, for now just write to console.)
Console.WriteLine("No record was selected from the database for method retrieveSingleProfile()");
throw new InvalidOperationException("An exception occured. No data was found while trying to retrienve a single profile.");
}
reader.Close();
}
return profile;
}
catch(InvalidOperationException e)
{
}
}
Added try catch in the correct place.
You need to step into the catch block for e to be set to the thrown InvalidOperationException:
catch (System.InvalidOperationException e)
{
int breakPoint = 0; //<- set a breakpoint here.
//Either you reach the breakpoint and have an InvalidOperationException, or you don't reach the breakpoint.
MessageBox.Show(e.Message);
}
Also make sure that the InvalidOperationException you throw is actually a System.InvalidOperationException and not some custom type of yours called "InvalidOperationException".
Like #Clemens said, you need to show all the relevant code.
As a quick test, this works just fine:
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Throwing error");
ThrowException();
}
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey(true);
}
static void ThrowException()
{
throw new InvalidOperationException("Blah blah blah");
}
}

Closing MySql datareader connection

So this is a little bit code-ceptionlike.
I have a function that is checking the last ID in a table, this function is called within another function. At the end of that function, I have another function that's opening another datareader.
Error:
There is already an open Datareader associated with this connection which must be closed first.
getLastIdfromDB()
public string getLastIdFromDB()
{
int lastIndex;
string lastID ="";
var dbCon = DB_connect.Instance();
if (dbCon.IsConnect())
{
MySqlCommand cmd2 = new MySqlCommand("SELECT ID FROM `competitor`", dbCon.Connection);
try
{
MySqlDataReader reader = cmd2.ExecuteReader();
while (reader.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message);
}
}
return lastID;
}
This function is later-on used in this function:
private void addPlayerBtn_Click(object sender, EventArgs e)
{
ListViewItem lvi = new ListViewItem(getLastIdFromDB());
.........................................^
... HERE
...
... irrelevant code removed
.........................................
var dbCon = DB_connect.Instance();
if (dbCon.IsConnect())
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO `competitor`(`ID`, `Name`, `Age`) VALUES(#idSql,#NameSql,#AgeSql)", dbCon.Connection);
cmd.Parameters.AddWithValue("#idSql", getLastIdFromDB());
cmd.Parameters.AddWithValue("#NameSql", playerName.Text);
cmd.Parameters.AddWithValue("#AgeSql", playerAge.Text);
try
{
cmd.ExecuteNonQuery();
listView1.Items.Clear();
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message);
dbCon.Connection.Close();
}
finally
{
updateListView();
}
}
}
What would be the best way for me to solve this problem and in the future be sure to close my connections properly?
UPDATE: (per request, included DB_connect)
class DB_connect
{
private DB_connect()
{
}
private string databaseName = "simhopp";
public string DatabaseName
{
get { return databaseName; }
set { databaseName = value; }
}
public string Password { get; set; }
private MySqlConnection connection = null;
public MySqlConnection Connection
{
get { return connection; }
}
private static DB_connect _instance = null;
public static DB_connect Instance()
{
if (_instance == null)
_instance = new DB_connect();
return _instance;
}
public bool IsConnect()
{
bool result = true;
try
{
if (Connection == null)
{
if (String.IsNullOrEmpty(databaseName))
result = false;
string connstring = string.Format("Server=localhost; database={0}; UID=root;", databaseName);
connection = new MySqlConnection(connstring);
connection.Open();
result = true;
}
}
catch (Exception ex)
{
Console.Write("Error: " + ex.Message);
}
return result;
}
public void Close()
{
connection.Close();
}
}
}
You are trying to have multiple open readers on the same connection. This is commonly called "MARS" (multiple active result sets). MySql seems to have no support for it.
You will have to either limit yourself to one open reader at a time, or use more than one connection, so you can have one connection for each reader.
My suggestion would be to throw away that singleton-like thingy and instead use connection pooling and proper using blocks.
As suggested by Pikoh in the comments, using the using clause indeed solved it for me.
Working code-snippet:
getLastIdFromDB
using (MySqlDataReader reader2 = cmd2.ExecuteReader()) {
while (reader2.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
Your connection handling here is not good. You need to ditch the DB_connect. No need to maintain a single connection - just open and close the connection each time you need it. Under the covers, ADO.NET will "pool" the connection for you, so that you don't actually have to wait to reconnect.
For any object that implements IDisposable you need to either call .Dispose() on it in a finally block, or wrap it in a using statement. That ensures your resources are properly disposed of. I recommend the using statement, because it helps keep the scope clear.
Your naming conventions should conform to C# standards. Methods that return a boolean should be like IsConnected, not IsConnect. addPlayerBtn_Click should be AddPlayerButton_Click. getLastIdFromDB should be GetlastIdFromDb or getLastIdFromDatabase.
public string GetLastIdFromDatabase()
{
int lastIndex;
string lastID ="";
using (var connection = new MySqlConnection(Configuration.ConnectionString))
using (var command = new MySqlCommand("query", connection))
{
connection.Open();
MySqlDataReader reader = cmd2.ExecuteReader();
while (reader.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
return lastID;
}
Note, your query is bad too. I suspect you're using a string data type instead of a number, even though your ID's are number based. You should switch your column to a number data type, then select the max() number. Or use an autoincrementing column or sequence to get the next ID. Reading every single row to determine the next ID and incrementing a counter not good.

How to return value from database into a variable

static float ExecuteQueryWithResult_fl(SqlConnection connection, string query)
{
using (SqlCommand command = new SqlCommand(query, connection))
{
float prev_val = ((float)command.ExecuteScalar());
return prev_val;
}
}
Call :
float f = ExecuteQueryWithResult_fl(connection, prev_status);
Iam using this in a client application that communicates with server , whenever this line is about to be executed : The connection breaks ! No error comes out . What may be the problem ??
public static void update_data_base(string type_id,int station, int ioa, byte by_val, float fl, uint bcr, bool is_float, bool is_bcr_iti,byte ov, byte bl, byte sb,byte nt, byte iv, byte seq, byte cy, byte ca)
{
string connectionString = "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=C:\\Users\\Ahmed Aek Ben Jemia\\Desktop\\newest\\command combo\\1\\iec104_master_slave_rtu\\Combo_1.mdf;Integrated Security=True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
string updateCommand = null,updateCommand1=null;
connection.Open();
ConnectionState state = connection.State;
float f = 0;
string prev_status = string.Format("SELECT STATUS FROM ") + type_id + string.Format("_Table WHERE ASDU={0} AND IOA={1}", station, ioa);
try
{
f = ExecuteQueryWithResult_fl(connection, prev_status);
}
catch (Exception e)
{
SetText2(e.ToString());
}
}
}
Error : System.InvalidCastException: Specified cast is not valid
PS : I can get string & byte values from database , this only happens with float and int.
Try the following and ensure your that your connection is open already.
static float ExecuteQueryWithResult_fl(SqlConnection connection, string query) {
try {
using (SqlCommand command = new SqlCommand(query, connection))
{
var prev_val = command.ExecuteScalar().ToString() == null ? default(float) : float.Parse(command.ExecuteScalar().ToString());;
return prev_val;
}
}
catch (Exception x)
{
Console.WriteLine("Error fetching due to {0}", x.Message);
return default(float);
}
}
Update:
Replace your query with:
string prev_status = string.Format("SELECT cast(STATUS as float) prev_status FROM {0}_Table WHERE ASDU={1} AND IOA={2}",type_id, station, ioa);
What you have looks ... usable (although I'd be very concerned about how you are passing in parameters); your code works fine when called like this:
public static void Main()
{
float f;
using(var conn = new SqlConnection("Server=.;Integrated Security=SSPI"))
{
conn.Open();
f = ExecuteQueryWithResult_fl(conn, "select cast(1.23 as float(24))");
}
Console.WriteLine(f); // 1.23
}
So the problem isn't the method you've shown (by itself). To understand what is happening, you should use a debugger and see what happens. My guess would be one of:
an invalid cast (the difference between float in C# and the SQL Server data types)
invalid SQL from concatenating values into the query (a very very bad thing to do)
combined with calling code that is swallowing an Exception without displaying it to you. The debugger will tell you, once you have a break-point at the location that isn't working.

Parameter '?user_email' not found in the collection

I am using MySql 5.6x with Visual Studio 2015, windows 10, 64-bit. C# as programming language. In my CRUD.cs (Class file) i have created the following method:
public bool dbQuery(string sql,string[] paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null){
foreach(string i in paramList){
string[] valus = i.Split(',');
string p = valus[0];
string v = valus[1];
cmd.Parameters[p].Value = v;
}
}
if (cmd.ExecuteNonQuery() > 0)
{
flag = true;
}
}
catch (Exception exc)
{
error(exc);
}
}
I am passing the query and Parameters List like this:
protected void loginBtn_Click(object sender, EventArgs e)
{
string sql = "SELECT * FROM dept_login WHERE (user_email = ?user_email OR user_cell = ?user_cell) AND userkey = ?userkey";
string[] param = new string[] {
"?user_email,"+ userid.Text.ToString(),
"?user_cell,"+ userid.Text.ToString(),
"?userkey,"+ userkey.Text.ToString()
};
if (db.dbQuery(sql, param))
{
msg.Text = "Ok";
}
else
{
msg.Text = "<strong class='text-danger'>Authentication Failed</strong>";
}
}
Now the problem is that after the loop iteration complete, it directly jumps to the catch() Block and generate an Exception that:
Parameter '?user_email' not found in the collection.
Am i doing this correct to send params like that? is there any other way to do the same?
Thanks
EDIT: I think the best way might be the two-dimensional array to collect the parameters and their values and loop then within the method to fetch the parameters in cmd.AddWidthValues()? I may be wrong...
In your dbQuery you don't create the parameters collection with the expected names, so you get the error when you try to set a value for a parameter that doesn't exist
public bool dbQuery(string sql,string[] paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null){
foreach(string i in paramList){
string[] valus = i.Split(',');
string p = valus[0];
string v = valus[1];
cmd.Parameters.AddWithValue(p, v);
}
}
if (cmd.ExecuteNonQuery() > 0)
flag = true;
}
catch (Exception exc)
{
error(exc);
}
}
Of course this will add every parameter with a datatype equals to a string and thus is very prone to errors if your datatable columns are not of string type
A better approach would be this one
List<MySqlParameter> parameters = new List<MySqlParameter>()
{
{new MySqlParameter()
{
ParameterName = "?user_mail",
MySqlDbType= MySqlDbType.VarChar,
Value = userid.Text
},
{new MySqlParameter()
{
ParameterName = "?user_cell",
MySqlDbType= MySqlDbType.VarChar,
Value = userid.Text
},
{new MySqlParameter()
{
ParameterName = "?userkey",
MySqlDbType = MySqlDbType.VarChar,
Value = userkey.Text
},
}
if (db.dbQuery(sql, parameters))
....
and in dbQuery receive the list adding it to the parameters collection
public bool dbQuery(string sql, List<MySqlParameter> paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null)
cmd.Parameters.AddRange(paramList.ToArray());
if (cmd.ExecuteNonQuery() > 0)
{
flag = true;
}
}
catch (Exception exc)
{
error(exc);
}
}
By the way, unrelated to your actual problem, but your code doesn't seem to close and dispose the connection. This will lead to very nasty problems to diagnose and fix. Try to use the using statement and avoid a global connection variable
EDIT
As you have noticed the ExecuteNonQuery doesn't work with a SELECT statement, you need to use ExecuteReader and check if you get some return value
using(MySqlDataReader reader = cmd.ExecuteReader())
{
flag = reader.HasRows;
}
This, of course, means that you will get troubles when you want to insert, update or delete record where instead you need the ExecuteNonQuery. Creating a general purpose function to handle different kind of query is very difficult and doesn't worth the work and debug required. Better use some kind of well know ORM software like EntityFramework or Dapper.
Your SQL Commands' Parameters collection does not contain those parameters, so you cannot index them in this manner:
cmd.Parameters[p].Value = v;
You need to add them to the Commands' Parameters collection in this manner: cmd.Parameters.AddWithValue(p, v);.

Incorrect Syntax near Where for an Update query

Here is the update query which i am using to update a table. It throws me an exception "Incorrect Syntax near Where" Why is that exception for? i have no idea.
public bool UpdateLocationCountintoMerchantPackage(int PackageID, long MerchantID,int LocationCount)
{
try
{
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("#packageID",PackageID),
new SqlParameter("#merchantID",MerchantID ),
new SqlParameter("#locationCount",LocationCount )
};
string CommandText = string.Empty;
CommandText = "Update Merchant_Package SET LocationCount Where MerchantID=#MerchantID";
string ConnectionString = DbConnectionStrings.GetDbConnectionString();
SqlHelper.ExecuteNonQuery(ConnectionString, System.Data.CommandType.Text, CommandText, parameters);
return true;
}
catch (SqlException ex)
{
LogError("Error Occurred When Saving Merchant Location Count Data : MerchantID:" + MerchantID.ToString(), ex);
return false;
}
}
this function is called from
protected void imgbtnSubmit_Click(object sender, ImageClickEventArgs e)
{
UpdatePaymentInfo();
string QueryString = Request.QueryString.ToString();
if (string.Equals(QueryString, "MerchantProfilePages"))
{
Response.Redirect(ApplicationData.URL_ADD_PROFILE_PAGE, false);
Merchant mrchnt = new Merchant();
int PackId = mrchnt.PackageID;
int x = GetLocationCount() + 1;
mrchnt.UpdateLocationCountintoMerchantPackage(PackId, merchantId, x);
}
It's an issue with your "SET LocationCount" - you're not setting it equal to anything. That's why it's complaining about the WHERE.
Use SQL like:
Update Merchant_Package SET LocationCount=#LocationCount
Where MerchantID=#MerchantID
Your error on the 1st line was reported when WHERE was encountered

Categories

Resources