I am trying to query the MySQL database from a c# application. Below is the code , here I am using parameterized query
public static void ValidateName(MySqlConnection conn,List<Employee> EmpList, string Group)
{
string selectQuery = "Select Name from Employee where Group = #Group AND #Name in (FirstName, LastName);";
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
for (int i = 0; i < EmpList.Count; i++)
{
cmd.Parameters.Add("#Group", MySqlDbType.VarChar).Value = Group;
cmd.Parameters.Add("#Name", MySqlDbType.VarChar).Value = EmpList[i].Name;
var reader = cmd.ExecuteReader();
List<string> lineList = new List<string>();
while (reader.Read())
{
lineList.Add(reader.GetString(0));
}
if (lineList.Count <=0)
{
WriteValidationFailure(EmpList[i], "Failed");
}
}
}
But the above code is throwing error in below line saying
cmd.Parameters.Add("#Group", MySqlDbType.VarChar).Value = Group;
An unhandled exception of type 'MySql.Data.MySqlClient.MySqlException'
occurred in MySql.Data.dll' #Group has already been defined
This is happening because you are adding the same set of parameters in each iterations. You can either clear then in each iteration or else add them before starting the loop and change the value of existing parameter during each iteration. I think second option would be great. One more thing I have to specify here is about the reader, you have to use reader as an using variable so that each time it will get disposed at the end of the using block and your code works fine. Which means you can try something like this:
using (MySqlCommand cmd = new MySqlCommand(selectQuery, conn))
{
cmd.Parameters.Add(new MySqlParameter("#Group", MySqlDbType.VarChar));
cmd.Parameters.Add(new MySqlParameter("#Name", MySqlDbType.VarChar));
for (int i = 0; i < EmpList.Count; i++)
{
cmd.Parameters["Group"].Value = group;
cmd.Parameters["Name"].Value = EmpList[i].Name;
// rest of code here
using (MySqlDataReader reader = cmd.ExecuteReader())
{
// Process reader operations
}
}
}
Related
string query = "SELECT date(EDate,'utc'),Tag,Valuex,Note from collections where Account_Number = '1010011' AND Edate >= '2021-01-01'";
using (SQLiteCommand insertCommand = new SQLiteCommand(query, connection))
{
using (SQLiteDataReader dr = insertCommand.ExecuteReader())
{
var newentry = new List<Values>();
while (dr.Read())
{
newentry.Add(new Values()
{
Date = dr["EDate"].ToString(),
Tag = dr["Tag"].ToString(),
Value = dr["Valuex"].ToString(),
Note = dr["Note"].ToString(),
});
}
dr.Close();
Closeconnection();
return newentry;
}
}
getting following error on the above code
Exception thrown: 'System.IndexOutOfRangeException' in System.Data.SQLite.dll
Error System.IndexOutOfRangeException: Index was outside the bounds of the array.
you're reading 'EDate' with dr["EDate"] and it does not exist in the Query you need to add it to your select statement!
string query = "SELECT date(EDate,'utc') as EDate, Tag, Valuex, Note from collections where Account_Number = '1010011' AND Edate >= '2021-01-01'";
When I execute the following code in C#, I can insert one record without issues. When I have two objects in my collection, I get the following error:
The variable name '#scoreboardId' has already been declared. Variable names must be unique within a query batch or stored procedure
Is there a way to work around this batch exception?
public void insertActiveMonitorsForScoreboard(SqlConnection dbConn, SqlTransaction dbTrans, int scoreboardId,
ObservableCollection<AvailableMonitorBo> availableMonitorsForAddOC)
{
using (SqlCommand dbCommand = new SqlCommand(CreateAndDisplaySQLStrings.INSERT_SCOREBOARD_MONITORS, dbConn))
{
dbCommand.Transaction = dbTrans;
foreach (AvailableMonitorBo bo in availableMonitorsForAddOC)
{
if (bo.IsActive)
{
dbCommand.Parameters.Add("scoreboardId", SqlDbType.Int).Value = scoreboardId;
dbCommand.Parameters.Add("availableMonitorId", SqlDbType.Int).Value = bo.AvailableMonitorId;
dbCommand.ExecuteNonQuery();
}
}
}
}
Try to add the parameters only once and subsequently only change their values.
public void insertActiveMonitorsForScoreboard(SqlConnection dbConn, SqlTransaction dbTrans, int scoreboardId,
ObservableCollection<AvailableMonitorBo> availableMonitorsForAddOC) {
using (SqlCommand dbCommand = new SqlCommand(CreateAndDisplaySQLStrings.INSERT_SCOREBOARD_MONITORS, dbConn)) {
dbCommand.Transaction = dbTrans;
dbCommand.Parameters.Add("scoreboardId", SqlDbType.Int);
dbCommand.Parameters.Add("availableMonitorId", SqlDbType.Int);
foreach (AvailableMonitorBo bo in availableMonitorsForAddOC) {
if (bo.IsActive) {
dbCommand.Parameters["scoreboardId"].Value = scoreboardId;
dbCommand.Parameters["availableMonitorId"].Value = bo.AvailableMonitorId;
dbCommand.ExecuteNonQuery();
}
}
}
}
Another approach is to put the SqlCommand inside your loop. This has the advantage that the SqlCommand is completely new for each loop, so nothing is carried over between iterations. This does not matter in this example, but in other cases it might.
public void insertActiveMonitorsForScoreboard(SqlConnection dbConn, SqlTransaction dbTrans, int scoreboardId,
ObservableCollection<AvailableMonitorBo> availableMonitorsForAddOC) {
foreach (AvailableMonitorBo bo in availableMonitorsForAddOC) {
if (bo.IsActive) {
using (SqlCommand dbCommand = new SqlCommand(CreateAndDisplaySQLStrings.INSERT_SCOREBOARD_MONITORS, dbConn)) {
dbCommand.Transaction = dbTrans;
dbCommand.Parameters.Add("scoreboardId", SqlDbType.Int).Value = scoreboardId;
dbCommand.Parameters.Add("availableMonitorId", SqlDbType.Int).Value = bo.AvailableMonitorId;
dbCommand.ExecuteNonQuery();
}
}
}
}
I'm new to C#, and write this code for calling a SQL Server stored procedure:
using (SqlConnection con = new SqlConnection(Connection))
{
using (SqlCommand cmd = new SqlCommand("CheckValidbehzad", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#p_bank", SqlDbType.VarChar).Value = p_bank;
cmd.Parameters.Add("#p_pay_date", SqlDbType.VarChar).Value = p_pay_date;
cmd.Parameters.Add("#p_bill_id", SqlDbType.VarChar).Value = p_bill_id;
cmd.Parameters.Add("#p_payment_id", SqlDbType.VarChar).Value = p_payment;
cmd.Parameters.Add("#p_ref_code", SqlDbType.VarChar).Value = p_ref_code;
cmd.Parameters.Add("#p_branch", SqlDbType.VarChar).Value = p_branch;
cmd.Parameters.Add("#p_channel_type", SqlDbType.VarChar).Value = p_channel;
cmd.Parameters.Add("#p_send_date", SqlDbType.VarChar).Value = p_send_date;
con.Open();
reader = cmd.ExecuteReader();
while (reader.Read())
{
//TempCode = reader["PaymentID"].ToString();
}
}
}
That stored procedure sometimes return ErrorNumber in result and sometimes it returns PaymentID. How can I check this scenario?
if( reader has ErrorNumber field) then
do something
else
do something else
Thanks all.
Not sure how exactly you can distinguish these two columns returned - if the column is present or missing (depending on the situation), then you can check for the presence of the column:
while (reader.Read())
{
try
{
int paymenIdPos = reader.GetOrdinal("PaymentID");
// if found --> read payment id
int paymentID = reader.GetInt32(paymenIdPos);
}
catch(IndexOutOfRangeException)
{
// if "PaymentID" is not found --> read the "ERrorNumber"
int errorCode = reader.GetInt32("ErrorNumber");
}
}
you can check with GetOrdinal, as marc_s suggested, or like this:
if (reader.GetSchemaTable().Select("ColumnName = 'PaymentId'").Length > 0)
{
//do something here with pamynet
}
else if (reader.GetSchemaTable().Select("ColumnName = 'ErrorNumber'").Length > 0)
{
//do your stuff here with error number
}
I am trying to return data using IEnumerable with given fields, where I am calling the the method I want to reference the data with given field name and return that.
Example, here is the function
public IEnumerable<IDataRecord> GetSomeData(string fields, string table, string where = null, int count = 0)
{
string sql = "SELECT #Fields FROM #Table WHERE #Where";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Fields", SqlDbType.NVarChar, 255).Value = where;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
Calling:
IEnumerable<IDataRecord> data = bw.GetSomeData("StaffCode, Perms", "BW_Staff", "StaffCode = 'KAA'");
What must I do to return the data this way or what way ?
string staffCode = data["StaffCode"].ToString();
string perms = data["Perms"].ToString();
Thanks for any help
your data variable is a collection of rows. You need to iterate over the collection to do something interesting with each row.
foreach (var row in data)
{
string staffCode = row["StaffCode"].ToString();
string perms = row["Perms"].ToString();
}
Update:
Based on your comment that you only expect GetSomeData(...) to return a single row, I'd suggest 1 of two things.
Change the signature of GetSomeData to return an IDataRecord. and remove "yield" from the implementation.
public IDataRecord GetSomeData(string fields, string table, string where = null, int count = 0)
{
string sql = "SELECT #Fields FROM #Table WHERE #Where";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Fields", SqlDbType.NVarChar, 255).Value = where;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
return (IDataRecord)rdr;
}
}
}
}
}
Or
var row = data.FirstOrDefault();
if (row != null)
{
string staffCode = row["StaffCode"].ToString();
string perms = row["Perms"].ToString();
}
Remarks:
Your implementation of GetSomeData is incomplete. You are not even using several of the parameters, most importantly the fields parameter. And conceptually in SQL you can't parameterize which fields get returned or which table gets used (etc.), but rather you need to construct a dynamic query and execute it.
Update 2
Here is an implementation of GetSomeData that constructs a proper query (in C# 6, let me know if you need it in an earlier version).
public IEnumerable<IDataRecord> GetSomeData(IEnumerable<string> fields, string table, string where = null, int count = 0)
{
var predicate = string.IsNullOrWhiteSpace(where) ? "" : " WHERE " + where;
string sql = $"SELECT { string.Join(",", fields) } FROM {table} {predicate}";
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
And here is how you would use it.
IEnumerable<IDataRecord> data = bw.GetSomeData(new[] { "StaffCode", "Perms" }, "BW_Staff", "StaffCode = 'KAA'");
You can either enumerate it or call .FirstOrDefault, it's your choice. Each time you call GetSomeData, it will run the query.
Update 3
GetSomeData implemented with earlier versions of C#
public IEnumerable<IDataRecord> GetSomeData(IEnumerable<string> fields, string table, string where = null, int count = 0)
{
var predicate = string.IsNullOrEmpty(where) ? "" : " WHERE " + where;
string sql = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", fields), table, predicate);
using (SqlConnection cn = new SqlConnection(db.getDBstring(Globals.booDebug)))
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
I have a stored procedure it returns a name so i need to get the name in in C#
so i just execute the Sp from C# and read the out put using ExecuteReader() like below
using (var objCommand = new SqlCommand("SpName", objConnection))
{
objCommand.Parameters.AddWithValue("#Param1", Param);
objCommand.Parameters.AddWithValue("#Purpose", Purpose);
objConnection.Open();
objCommand.CommandType = CommandType.StoredProcedure;
using (var reader = objCommand.ExecuteReader())
{
while (reader.Read())
{
objemailsend.Name = Convert.ToString(reader["Name"]);
}
}
}
objConnection.Close();
It gives an exception
Index Out of range exception
I am sure that the index names are same i mean the Sp also returns the same name
Name
----
name1
like above
then i tried something like below and now the exception disappears and it returns a numeric value i don't know from where the value coming from and it is not same as my SP result
objexample.Name = reader[0].ToString();
also tried
using (var reader = objCommand.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
objemailsend.Name = Convert.ToString(reader["Name"]);
}
}
}
But the same error
Can you somebody help me to solve my issue.
Please check this answer out
var returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
int id = (int) returnParameter.Value;
Try retrieving the value using index like objemailsend.Name = reader[1].ToString().
Where I have assumed 1 to be the index for name column.
As you are getting the Index Out of range execption this will help because here you are explicitly providing the index for the name column.
using (var objCommand = new SqlCommand("SpName", objConnection))
{
objCommand.Parameters.AddWithValue("#Param1", Param);
objCommand.Parameters.AddWithValue("#Purpose", Purpose);
objConnection.Open();
objCommand.CommandType = CommandType.StoredProcedure;
using (var reader = objCommand.ExecuteReader())
{
while (reader.Read())
{
objemailsend.Name = Convert.ToString(reader[1]);
}
}
}
objConnection.Close();