C# Excel add-in loops never terminate - c#

I have written an add-in that reads values from a spreadsheet and populates a database. When I execute the add-in in debug mode from Visual studio it works correctly the first time. Without stopping the debugger when I try to upload values from another spreadsheet using the add-in the loops in my add-in never seem to end. I control them using the used range of the active sheet and for some reason after the loop counter hits the range count it gets reinitialized to the starting value and hence my database spits out an SqlException due to a violation of the unique key constraint.
using (SqlConnection conn = DataConnection.GetConnection())
{
conn.Open();
using (SqlCommand myCommand = new SqlCommand(commandText, conn))
{
SqlParameter termIDParam = myCommand.Parameters.Add("#tid", SqlDbType.Int);
SqlParameter priceParam = myCommand.Parameters.Add("#price", SqlDbType.Decimal);
SqlParameter ContractDateParam = myCommand.Parameters.Add("#date", SqlDbType.DateTime);
SqlParameter pipelineIDParam = myCommand.Parameters.Add("#pid", SqlDbType.Int);
string pipeline = activeSheet.Cells[1, 1].Value2.ToString();
bool isNonDuplicate = true;
int startRow = (pipeline.ToLower().Equals("henry hub")) ? 3 : 4;
int startColumn = checkBox1.Checked ? 2 : 1;
for (int i = startRow; i <= range.Rows.Count & isNonDuplicate; i++)
{
for (int j = startColumn; j <= range.Columns.Count; j++)
{
if (range.Cells[i, j].Value2 != null && !range.Cells[i, j].Value2.ToString().Equals(" "))
{
string dateval = range.Cells[(startRow - 2), j].Value2.ToString();
double val = double.Parse(dateval);
DateTime contractDate = DateTime.FromOADate(val);
DateTime tempTerm = DateTime.FromOADate(activeSheet.Cells[i, 1].Value2);
string monthName = new DateTimeFormatInfo().GetAbbreviatedMonthName(tempTerm.Month);
string year = tempTerm.Year.ToString().Substring(2, 2);
string term = monthName + "-" + year;
double price = double.Parse(range.Cells[i,j].Value2.ToString());
SqlCommand subCommand = new SqlCommand();
subCommand.CommandText = "Select PipelineID from Pipeline where PipelineDescription='" + pipeline + "'";
subCommand.Connection = conn;
int pipeID = (int)subCommand.ExecuteScalar();
subCommand.CommandText = "Select TermID from Term where TermDescription = '" + term + "'";
int termID = (int)subCommand.ExecuteScalar();
termIDParam.Value = termID;
priceParam.Value = price;
ContractDateParam.Value = contractDate;
pipelineIDParam.Value = pipeID;
myCommand.Parameters["#tid"] = termIDParam;
myCommand.Parameters["#price"] = priceParam;
myCommand.Parameters["#date"] = ContractDateParam;
myCommand.Parameters["#pid"] = pipelineIDParam;
myCommand.ExecuteNonQuery();
}
}
double progress = (double)i / range.Rows.Count * 100;
bgw.ReportProgress(Convert.ToInt32(progress));
}
}
}
The i loop after it hits the limit(range.rows.count) gets reinitalised to 'startRow' and it happens only when I dont stop the debugger after processing one sheet and continue processing multiple sheets.
I am at my wits end tring to figure out what could cause this. Please help
Update
I forgot to add that this method is part of the Background Worker DoWork() method. When I try to execute it without using background worker I have no issues. I am forced to think the DoWork () method does not end and keeps calling the method causing the reinitialization. How can I let the DoWork method know that the work is over.

Related

update a table by using for loop with parameters in C#

I have a table with some columns like
now I want to use a for loop to set
out_0 = 0,
out_1 = 1,
out_2 = 2,
out_3 = 3,
out_4 = 4
so I update it with such code as
string sql = "update exchange_out set #column = #id where member_id = 6;";
SqlCommand cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#column", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
int n = 0;
for (int i = 0; i < 5; i++)
{
cmd.Parameters["#column"].Value = "out_" + i;
cmd.Parameters["#gid"].Value = i;
n = cmd.ExecuteNonQuery();
MessageBox.Show("" + n);
}
but it didn't write any data into the table while it literally did five times of updating, because the messagebox returns "1" five times.
finally I solve this by
for (int i = 0; i < 5; i++){
sql = string.Format("update exchange_out set {0} = {1} where member_id = 6", "out_" + i, i);
}
but I'm still wondering why it didn't work by adding parameters?
any respond will be appreciated. :)
I'm still wondering why it didn't work by adding parameters?
Identifiers such as table and column names cannot be parameterized in this way, only data. Your attempt effectively runs a query like this:
update exchange_out set 'out_1' = 1 where member_id = 6;
It's the same in any programming language:
var data1 = "hello";
var whichData = "1";
Console.WriteLine(data+whichData); //it doesn't compile; you cannot programmatically build a variable name `data1` in this way
The way you found is reasonably the only way but you should still parameterize the data:
using var cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#data", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
for (int i = 0; i < 5; i++){
sql = string.Format("update exchange_out set out_{0} = #data where member_id = #id", i);
cmd.CommandText = sql;
cmd.Parameters["#data"].Value = ...
cmd.Parameters["#id].Value = 6;
...
You could also start with an SQL stub like "UPDATE t SET " and repeatedly concatenate on identifiers and parameters:
using var cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#data", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
var sql = "UPDATE exchange_out SET ";
for (int i = 0; i < 5; i++){
sql += string.Format("out_{0} = #data{0},", i);
cmd.Parameters["#data"+i].Value = ...
}
sql = sql.TrimEnd(',');
sql += " where member_id = #id";
cmd.Parameters["#id"].Value = 6;
cmd.CommandText = sql;
...
This does the update in one operation, running a query like UPDATE t SET out_1 = #data1, out_2 = #data2 ...
These are safe from SQL injection because your code controls the entire SQL; there isn't any capacity for a user to provide '; DROP TABLE Students;-- as the {0} going into the identifier in this case but take care that you don't arrange for it to be possible (don't let the user provide identifier text)..
Your non-parameter attempt is also safe from SQL injection in this case by virtue of inserting intergers that you control, rather than strings you don't, but be careful you don't universally apply the technique and one day include user-suppied strings. If you do find yourself in that suitable you should use something like a whitelist of user input - any string identifier provided by the user that isn't whitelisted should not be put in the SQL

C# How to do loop variable for query (where)

Please help I can't understand about variable for query by when in SQL command. -> get value and do loop again and again (get and change) sorry I'm not good english
This code :
var ee = 0;
var command = new SqlCommand("SELECT Values,date FROM db_db where date ='" + ee ", connection);
var reader = command.ExecuteReader();
var dt = 8;
for (int i = 0; i <= dt; i++)
{
dataGridView1.Columns.Add("A", starttime.AddMonths(i).ToString("MM", seCultureInfo) + "/" + starttime.AddMonths(i).ToString("yyyy", seCultureInfo));
mm = "1";
}
while (reader.Read())
{
var value = reader.GetDecimal(2);
// var column = new DataGridViewTextBoxColumn();
// column.HeaderText = header.ToString();
// this.dataGridView1.Columns.Add(column);
if (dataGridView1.RowCount < 2)
{
this.dataGridView1.Rows.Add();
}
this.dataGridView1.Rows[0].Cells[columnIndex].Value = value;
/* This --------------->*/ ee++;
columnIndex++;
}
Look at "ee". I want to keep value "ee" and bring it back in query command by new "ee".
Last date of value was wrong it's correct at 07/2015
If I got your question correctly , you want to reuse the SQL but increasing the 'ee' variable .
It is impossible .
If your business logic is about query based on different date, You have to build the SQL command again and again .

Log each statement of SqlDataAdapter C#

Is it possible to log exactly each individual statement which SqlDataAdapter executes on mysql Database, while using .Update() Method in C#?
(Without having to use SQLProfiler or any other third party programm, but pure C# code)
You could handle the DataAdapter events like RowUpdating or RowUpdated.
So for your MySql database:
void OnRowUpdated(object sender, MySqlRowUpdatedEventArgs args)
{
string sql = args.Command.CommandText;
bool isStoredProcedure = args.Command.CommandType == CommandType.StoredProcedure;
foreach (MySql.Data.MySqlClient.MySqlParameter p in args.Command.Parameters)
{
string paramName = p.ParameterName;
DbType dbType = p.DbType;
MySqlDbType dbType2 = p.MySqlDbType;
object value = p.Value;
}
}
These events are triggered for every row that gets inserted, updated or deleted.
This is the way I solved my problem, thought I'd share it for anyone looking for an idea.
#region generate SQL Update Script
static void da_RowUpdating(object sender, SqlRowUpdatingEventArgs e)
{
string sqlCommand = e.Command.CommandText;
for (int i = 0; i < sqlCommand.Length; i++)
{
string substring = "";
string paramvalue = "";
int check = 0;
int index = 0;
substring = sqlCommand.Substring(i, 1);
if (substring == "#")
{
if (Int32.TryParse(sqlCommand.Substring(i + 3, 1), out check))
{
index = Convert.ToInt32(sqlCommand.Substring(i + 2, 2));
paramvalue = e.Command.Parameters[Convert.ToInt32(sqlCommand.Substring(i + 2, 2)) - 1].Value.ToString();
sqlCommand = sqlCommand.Remove(i, 4);
}
else
{
index = Convert.ToInt32(sqlCommand.Substring(i + 2, 1));
paramvalue = e.Command.Parameters[index - 1].Value.ToString();
sqlCommand = sqlCommand.Remove(i, 3);
}
sqlCommand = sqlCommand.Insert(i, paramvalue);
}
}
sw.WriteLine(sqlCommand);
sw.Flush();
}
#endregion generate SQL Update Script

Passing Column name as string in mysql Insert query

this is what i am trying to do after receiving string from the serial port. i get whitespace between the data so i put two loops to eliminate them. i want to recieve data spanning multiple columns and a single row for every single run of do while loop.. Thanks in Advance
string text = sp.readline();
for (int i = 0; i < text.Length; )
{
p = text[i].ToString();
if (p != " ")
{
do
{
x += text[i].ToString();
s = text[i].ToString();
i++;
} while (s != " ");
try
{
string col = "column" + no.ToString();
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "INSERT INTO testdata("+col+")VALUES(?data)";
cmd.Parameters.Add("?data", MySqlDbType.VarChar).Value = x;
cmd.ExecuteNonQuery();
x = "";
p = "";
no++;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
} i++;
}
Sorry to say, you cannot, in any dialect of SQL, provide a table or column name as a bindable variable (or parameter). If it's working for MySQL that's terrific, but if you change over to any other DBMS make and model, it will suddenly stop working.
Also, INSERT means create a new row. You'll either need to insert all the column values at once in a single INSERT statement, or figure out how to INSERT one row and then UPDATE it for each new column value.
if you want to insert a single row having multiple column, then for loop is not required
following is for three columns
int no = 2;
cmd.CommandText = "INSERT INTO testdata(?col1,?col2,?col3)VALUES(?data1,?data2,?data3)";
cmd.Parameters.Add("?col1", MySqlDbType.String).Value = col1;
cmd.Parameters.Add("?col2", MySqlDbType.String).Value = col2;
cmd.Parameters.Add("?col3", MySqlDbType.String).Value = col3;
cmd.Parameters.Add("?data1", MySqlDbType.VarChar).Value = x1;
cmd.Parameters.Add("?data2", MySqlDbType.VarChar).Value = x2;
cmd.Parameters.Add("?data3", MySqlDbType.VarChar).Value = x3;
cmd.ExecuteNonQuery();

Sql query execution inside a for loop

for (int i = 0; i <= GridView1.Rows.Count - 1; i++)
{
string toemail = GridView1.Rows[i].Cells[2].Text;
string FID1 = GridView1.Rows[i].Cells[0].Text;
GridViewRow row = GridView1.Rows[i];
CheckBox Ckbox = (CheckBox)row.FindControl("CheckBoxMark1");
if (Ckbox.Checked == true)
{
sendMail(toemail);
//ClientScript.RegisterStartupScript(Page.GetType(), "validation", "<script language='javascript'>alert('Email send Succesfully')</script>");
ClientScript.RegisterStartupScript(Page.GetType(), "validation", "<script language='javascript'>alert('Email sent Succesfully on " + test + "')</script>");
cn1.Open();
//cmd4.CommandText = "Insert into TrackingFaculty_det (EmailsentDate) values (#EmailsentDate) WHERE FID=#FID";
cmd4.CommandText = "update TrackingFaculty_det SET EmailsentDate=#Email WHERE FID=#FID ";
cmd4.CommandType = CommandType.Text;
cmd4.Connection = cn1;
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4.Parameters["#Email"].Value = sdt;
cmd4.Parameters.Add("#FID",SqlDbType.VarChar,10);
cmd4.Parameters["#FID"].Value = FID1;
cmd4.ExecuteNonQuery();
cn1.Close();
}
}
//This is a part of c# code along with asp.net
The problem arises if whenever the for loop gets executed the updation should be done in the database but when for loop executes more than once the update query will give a error as The variable name '#Email' has already been declared. Variable names must be unique within a query batch or stored procedure..Any solution for this?
Just move the invariant part of your loop outside the loop. That means, the initialization of the SqlCommand, the opening of the connection and the creation of the parameters collection.
Then inside the loop just change the value of the parameters and execute. (This will be always faster than recreating the same list of parameters inside the loop)
SqlCommand cmd4 = new SqlCommand("update TrackingFaculty_det " +
"SET EmailsentDate=#Email WHERE FID=#FID", cn1);
cn1.Open();
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4.Parameters.Add("#FID",SqlDbType.VarChar,10);
for (int i = 0; i <= GridView1.Rows.Count - 1; i++)
{
.....
if (Ckbox.Checked == true)
{
....
cmd4.Parameters["#Email"].Value = sdt;
cmd4.Parameters["#FID"].Value = FID1;
cmd4.ExecuteNonQuery();
}
}
cn1.Close();
Try clearing command parameters -
cmd4.Parameters.Clear();
and then add the parameter
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
So your final code would be-
cmd4.Parameters.Clear(); // <- Just add this line
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4 object should be refreshed everytime.
cmd4.Parameters.Add("#Email", SqlDbType.DateTime, 8);
cmd4.Parameters["#Email"].Value = sdt;
cmd4.Parameters.Add("#FID",SqlDbType.VarChar,10);
cmd4.Parameters["#FID"].Value = FID1;
your adding the same parameters more than one time to parameter list of "cmd4"
Clear your paramters before adding once again same parameters
cmd4.Parameters.Clear();
check the Run Stored Procedure with table data as parameter
or second is create string with below example and exec(string) in sql server
sqlstr= "update TrackingFaculty_det SET EmailsentDate=2#2.com WHERE FID=1; update TrackingFaculty_det SET EmailsentDate=1#1.com WHERE FID=#FID ;pdate TrackingFaculty_det SET EmailsentDate=2#2.com WHERE FID=1;"

Categories