c# code error The name 'i' does not exist - c#

in line
urls[i] = Reader.GetValue(i).ToString();
it say Error 1 The name 'i' does not exist in the current context
how can I fix it
private void Form1_Load(object sender, EventArgs e)
{
string MyConString = "SERVER=192.168.0.78;" +
"DATABASE=webboard;" +
"UID=aimja;" +
"PASSWORD=aimjawork;" +
"charset=utf8;";
MySqlConnection connection = new MySqlConnection(MyConString);
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
command.CommandText = "SELECT url FROM `listweb` WHERE `url` IS NOT NULL AND ( `webbordkind` = '¿¿¿¿¿¿¿¿¿¿¿¿' ) and `nourl`= 'n' order by province, amphore limit 4 ";
connection.Open();
Reader = command.ExecuteReader();
string[] urls = new string[2];
string thisrow = "";
string sumthisrow = "";
string urlname ;
while (Reader.Read())
{
thisrow = "";
for (int i = 0; i < Reader.FieldCount; i++)
thisrow += Reader.GetValue(i).ToString();
urlname = Reader.GetValue(i).ToString();
urls[i] = Reader.GetValue(i).ToString();
// System.IO.File.AppendAllText(#"C:\file.txt", thisrow + " " + Environment.NewLine);
sumthisrow = sumthisrow + thisrow;

You need to add braces to your for loop otherwise it only loops the first statement.
for (int i = 0; i < Reader.FieldCount; i++)
{
thisrow +=  Reader.GetValue(i).ToString();
urlname = Reader.GetValue(i).ToString();
urls[i] =  Reader.GetValue(i).ToString();
}

You are missing braces here:
for (int i = 0; i < Reader.FieldCount; i++)
{
thisrow += Reader.GetValue(i).ToString();
urlname = Reader.GetValue(i).ToString();
urls[i] = Reader.GetValue(i).ToString();
}
I'd also advise you not to create strings by concatenating in a loop. Put them in a List<string> first then at the end convert it to an array (except in .NET 4.0 or newer where this step is not required) and use string.Join. As well as giving better performance this allows allows you to add a separator between the fields, which I assume you want...
If you don't need a separator then you can use a StringBuilder.

Your braces are missing for the FOR loop. The variable i is available only within the FOR loop which is only one line after your loop in your case.
for (int i = 0; i < Reader.FieldCount; i++)
{
thisrow += Reader.GetValue(i).ToString();
urlname = Reader.GetValue(i).ToString();
urls[i] = Reader.GetValue(i).ToString();
}

Related

C# List<> - Insert into database

I have this app where i get data from a TextBox, insert it into a List<> and then display a new line in the CheckBoxList.
Example:
List<string> quantidade = new List<string>();
for (int i = 0; i < CheckBoxListLinhas.Items.Count; i++)
{
quantidade.Add(TextBoxQuantidade.Text.ToString());
}
List<string> artigo = new List<string>();
for (int i = 0; i < CheckBoxListLinhas.Items.Count; i++)
{
artigo.Add(TextBoxArtigo.Text.ToString());
}
List<string> valor = new List<string>();
for (int i = 0; i < CheckBoxListLinhas.Items.Count; i++)
{
valor.Add(TextBoxValor.Text.ToString());
}
/*List<string> artigo = new List<string>();
for (int i = 0; i < CheckBoxListLinhas.Items.Count; i++)
{
artigo.Add(TextBoxArtigo.Text.ToString());
}*/
CheckBoxListLinhas.Items.Add(new ListItem("Quantidade: " + TextBoxQuantidade.Text + " Artigo: " + TextBoxArtigo.Text + " Valor: " + TextBoxValor.Text) + " Anexo: " + FileUpload1.FileName.ToString());
And then I want to insert every row from that List<> to the database and I already have this example:
SqlCommand sqlInsertList = new SqlCommand("Insert into linhas (quantidade,descricao,valor) VALUES(#quantidade,#descricao,#valor)", sqlConn);
sqlInsertList.Parameters.AddWithValue("#quantidade", );
sqlInsertList.Parameters.AddWithValue("#descricao", TextBoxArtigo.Text);
sqlInsertList.Parameters.AddWithValue("#valor", float.Parse(TextBoxValor.Text, CultureInfo.InvariantCulture.NumberFormat));
sqlConn.Open();
sqlTran = sqlConn.BeginTransaction();
sqlInsert.Transaction = sqlTran;
sqlInsert.ExecuteNonQuery();
sqlTran.Commit();
What is the easiest way I can do that and adapt my SQLInsert?
SqlCommand sqlInsertList = new SqlCommand("Insert into linhas (quantidade,descricao,valor) VALUES(#quantidade,#descricao,#valor)", sqlConn);
sqlConn.Open();
sqlTran = sqlConn.BeginTransaction();
for (int i = 0; i < quantidade.Count; i++)
{
sqlInsertList.Transaction = sqlTran;
sqlInsertList.Parameters.Clear();
sqlInsertList.Parameters.AddWithValue("#quantidade", quantidade[i]);
sqlInsertList.Parameters.AddWithValue("#descricao", artigo[i]);
sqlInsertList.Parameters.AddWithValue("#valor", loat.Parse(valor[i], CultureInfo.InvariantCulture.NumberFormat));
sqlInsertList.ExecuteNonQuery();
}
sqlTran.Commit();

DataReader to .CSV with column names

I'm generating a csv file from an SqlDataReader, however it is not writing the column names, how can I make it write them? The code I'm using is as follows:
SqlConnection conn = new SqlConnection(myconn);
SqlCommand cmd = new SqlCommand("dbo.test", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
StringBuilder sb = new StringBuilder();
StreamWriter sw = new StreamWriter(myfilePath + "testfile.csv");
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
string value = reader[i].ToString();
if (value.Contains(","))
value = "\"" + value + "\"";
sb.Append(value.Replace(Environment.NewLine, " ") + ",");
}
sb.Length--; // Remove the last comma
sb.AppendLine();
}
conn.Close();
sw.Write(sb.ToString());
sw.Close();
Read all the column names and append it to sb then iterate reader.
SqlDataReader reader = cmd.ExecuteReader();
StringBuilder sb = new StringBuilder();
//Get All column
var columnNames = Enumerable.Range(0, reader.FieldCount)
.Select(reader.GetName) //OR .Select("\""+ reader.GetName"\"")
.ToList();
//Create headers
sb.Append(string.Join(",", columnNames));
//Append Line
sb.AppendLine();
while (reader.Read())
....
Using this solution i created an extension.
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="filename"></param>
/// <param name="path">if null/empty will use IO.Path.GetTempPath()</param>
/// <param name="extension">will use csv by default</param>
public static void ToCsv(this IDataReader reader, string filename, string path = null, string extension = "csv")
{
int nextResult = 0;
do
{
var filePath = Path.Combine(string.IsNullOrEmpty(path) ? Path.GetTempPath() : path, string.Format("{0}.{1}", filename, extension));
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine(string.Join(",", Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList()));
int count = 0;
while (reader.Read())
{
writer.WriteLine(string.Join(",", Enumerable.Range(0, reader.FieldCount).Select(reader.GetValue).ToList()));
if (++count % 100 == 0)
{
writer.Flush();
}
}
}
filename = string.Format("{0}-{1}", filename, ++nextResult);
}
while (reader.NextResult());
}
You can use SqlDataReader.GetName to get the column name
for (int i = 0; i < reader.FieldCount; i++)
{
string columnName = reader.GetName(i);
}
Also you can create an extension method like below:
public static List<string> ToCSV(this IDataReader dataReader, bool includeHeaderAsFirstRow, string separator)
{
List<string> csvRows = new List<string>();
StringBuilder sb = null;
if (includeHeaderAsFirstRow)
{
sb = new StringBuilder();
for (int index = 0; index < dataReader.FieldCount; index++)
{
if (dataReader.GetName(index) != null)
sb.Append(dataReader.GetName(index));
if (index < dataReader.FieldCount - 1)
sb.Append(separator);
}
csvRows.Add(sb.ToString());
}
while (dataReader.Read())
{
sb = new StringBuilder();
for (int index = 0; index < dataReader.FieldCount - 1; index++)
{
if (!dataReader.IsDBNull(index))
{
string value = dataReader.GetValue(index).ToString();
if (dataReader.GetFieldType(index) == typeof(String))
{
//If double quotes are used in value, ensure each are replaced but 2.
if (value.IndexOf("\"") >= 0)
value = value.Replace("\"", "\"\"");
//If separtor are is in value, ensure it is put in double quotes.
if (value.IndexOf(separator) >= 0)
value = "\"" + value + "\"";
}
sb.Append(value);
}
if (index < dataReader.FieldCount - 1)
sb.Append(separator);
}
if (!dataReader.IsDBNull(dataReader.FieldCount - 1))
sb.Append(dataReader.GetValue(dataReader.FieldCount - 1).ToString().Replace(separator, " "));
csvRows.Add(sb.ToString());
}
dataReader.Close();
sb = null;
return csvRows;
}
Example:
List<string> rows = null;
using (SqlDataReader dataReader = command.ExecuteReader())
{
rows = dataReader.ToCSV(includeHeadersAsFirstRow, separator);
dataReader.Close();
}
You can use the SqlDataReader.GetName method to get the name of a column, like this:
for(int i = 0; i < reader.FieldCount; i++)
{
string columnName = reader.GetName(i);
}
I developed following high performance extension
static void Main(string[] args)
{
SqlConnection sqlCon = new SqlConnection("Removed");
sqlCon.Open();
SqlCommand sqlCmd = new SqlCommand("Select * from Table", sqlCon);
SqlDataReader reader = sqlCmd.ExecuteReader();
string csv=reader.ToCSVHighPerformance(true);
File.WriteAllText("Test.CSV", csv);
reader.Close();
sqlCon.Close();
}
Extention:
public static string ToCSVHighPerformance(this IDataReader dataReader, bool includeHeaderAsFirstRow = true,
string separator = ",")
{
DataTable dataTable = new DataTable();
StringBuilder csvRows = new StringBuilder();
string row = "";
int columns ;
try
{
dataTable.Load(dataReader);
columns= dataTable.Columns.Count;
//Create Header
if (includeHeaderAsFirstRow)
{
for (int index = 0; index < columns; index++)
{
row += (dataTable.Columns[index]);
if (index < columns - 1)
row += (separator);
}
row += (Environment.NewLine);
}
csvRows.Append(row);
//Create Rows
for (int rowIndex = 0; rowIndex < dataTable.Rows.Count; rowIndex++)
{
row = "";
//Row
for (int index = 0; index < columns - 1; index++)
{
string value = dataTable.Rows[rowIndex][index].ToString();
//If type of field is string
if (dataTable.Rows[rowIndex][index] is string)
{
//If double quotes are used in value, ensure each are replaced by double quotes.
if (value.IndexOf("\"") >= 0)
value = value.Replace("\"", "\"\"");
//If separtor are is in value, ensure it is put in double quotes.
if (value.IndexOf(separator) >= 0)
value = "\"" + value + "\"";
//If string contain new line character
while (value.Contains("\r"))
{
value = value.Replace("\r", "");
}
while (value.Contains("\n"))
{
value = value.Replace("\n", "");
}
}
row += value;
if (index < columns - 1)
row += separator;
}
dataTable.Rows[rowIndex][columns - 1].ToString().ToString().Replace(separator, " ");
row += Environment.NewLine;
csvRows.Append(row);
}
}
catch (Exception ex)
{
throw ex;
}
return csvRows.ToString();
}

Writing a million rows to a text file

Please see the below code which I use for writing to a text file. But database fetches nearly 1 millions records, so can someone please advise a faster way to do this or how should I change the below mentioned code to get it working faster?
try
{
using (OleDbConnection connection = new OleDbConnection(ConnectionString))
{
OleDbCommand command = new OleDbCommand(queryString, connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(reader);
StreamWriter writer = new StreamWriter(FilePath + FileName);
var result = string.Empty;
for (int i = 0; i < dt.Rows.Count; i++)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
result += dt.Rows[i][j] + "|";
}
result += "\r\n";
}
writer.WriteLine(result);
reader.Close();
writer.Close();
Dts.TaskResult = (int)ScriptResults.Success;
}
}
You load 1 million records in a datatable and then loop again on that table to write each row.
Probably you could do the same thing, but in half the time if you read a single row and write it down:
OleDbDataReader reader = command.ExecuteReader();
StreamWriter writer = new StreamWriter(FilePath + FileName);
var result = string.Empty;
while(reader.Read())
{
for (int j = 0; j < reader.FieldCount; j++)
{
result += reader[j] + "|";
}
result += "\r\n";
}
writer.WriteLine(result);
Also, using a StringBuilder to buffer your read in memory and not constantly writing to disk could be very beneficial in this situation:
// This size is just for example purpose. Should be fine tuned
StringBuilder buffer = new StringBuilder(1048576);
while(reader.Read())
{
for (int j = 0; j < reader.FieldCount; j++)
{
buffer.Append(reader[j] + "|");
}
buffer.AppendLine();
if(buffer.Length > 1048576 - 1024)
{
writer.Write(buffer.ToString());
buffer.Length = 0;
}
}
writer.Write(buffer.ToString());

Variable in SqlCommand must be unique within a query batch.. but it is?

I am making a windows service to gather a bunch of information and I'm sending it to the DB. I know methodology below works because I have used it on other tables with no errors. But I had to expand my DELETE command to use to have two conditions, and now I'm receiving an error.
This is the error I am receiving: "The variable name '#deletedrive' has already been declared. Variable names must be unique within a query batch or stored procedure."
Here is my code (The ending left out because it simply is catches the exception we're getting. Also ignore commented lines):
private static void ServerSpaceTimerAction(object source, ElapsedEventArgs e, string InstallLocation)
{
//StreamWriter RecordServerSpace = new StreamWriter(InstallLocation + "\\Temp\\ServerSpaceTemp.csv");
try
{
ServerSpace GetSpace = new ServerSpace();
GetConfigurations Configs = new GetConfigurations();
Configs.GetServers();
Configs.GetDatabase();
var connection = new SqlConnection("Data Source=" + Configs.DataSource + "; Initial Catalog=" + Configs.DatabaseCatalog + "; Integrated Security=" + Configs.IntegratedSecurityProtocol);
connection.Open();
char[] delim = { ' ', ',' };
string sInsertServerSpace = "INSERT INTO ServerSpace (date_time, server, region, farm, technology, role, drive, total_space, free_space) VALUES (#dt, #ser, #reg, #farm, #tech, #role, #drive, #ts, #fs)";
string sDeleteServerSpace = "DELETE FROM ServerSpace WHERE server=#serd AND drive=#deletedrive";
foreach (string server in Configs.servers)
{
string temp;
SqlCommand cmdInsertServerSpace = new SqlCommand(sInsertServerSpace, connection);
SqlCommand cmdDeleteServerSapce = new SqlCommand(sDeleteServerSpace, connection);
Configs.GetServerAttributes(server);
if (Configs.technology != "SQL")
{
GetSpace.DriveSpaceByServer(server);
}
else
{
GetSpace.DriveSpaceByServerMount(server);
}
string[] driveStats = GetSpace.ServerSpaceStats.Split(delim);
temp = DateTime.Now.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#dt", temp);
temp = server.ToString();
cmdDeleteServerSapce.Parameters.AddWithValue("#serd", temp);
cmdInsertServerSpace.Parameters.AddWithValue("#ser", temp);
temp = Configs.regiongroup.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#reg", temp);
temp = Configs.farmgroup.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#farm", temp);
temp = Configs.technology.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#tech", temp);
temp = Configs.rolegroup.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#role", temp);
for (int i = 0; i < driveStats.Length; i++)
{
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#drive", temp);
cmdDeleteServerSapce.Parameters.AddWithValue("#deletedrive", temp);
i++;
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#ts", temp);
i++;
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#fs", temp);
cmdDeleteServerSapce.ExecuteNonQuery();
cmdInsertServerSpace.ExecuteNonQuery();
}
//RecordServerSpace.WriteLine(DateTime.Now + "," + server + "," + Configs.regiongroup + "," + Configs.farmgroup + "," + Configs.technology + "," + Configs.rolegroup + "," + GetSpace.ServerSpaceStats);
}
connection.Close();
Let me know if you may need anything else to reference.
You only need to add the parameters once. You are adding parameters each time through the loop. Change it so that you add the parameters once, but set their values each time toruhg the loop.
SqlCommand cmdDeleteServerSapce = new SqlCommand(sDeleteServerSpace, connection);
....
cmdInsertServerSpace.Parameters.AddWithValue("#drive", temp);
cmdDeleteServerSapce.Parameters.AddWithValue("#deletedrive", temp));
for (int i = 0; i < driveStats.Length; i++)
{
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters["#drive"].value = temp;
cmdDeleteServerSapce.Parameters["#deletedrive"].value = temp;
.....
cmdDeleteServerSapce.ExecuteNonQuery();
cmdInsertServerSpace.ExecuteNonQuery();
}
It looks like you're using the command in the loop. You only need to put the parameter in once (AddWithValue). You can alter it in the subsequent attempts but don't add it again.
You should do:
cmdDeleteServerSapce.Parameters.Add("#deletedrive", SqlDbType.VarChar);
Outside the loop.
and
cmdDeleteServerSapce.Parameters["#deletedrive"].Value = temp;
Inside the loop.
I believe you are missing a call to cmdInsertServerSpace.ExecuteNonQuery() and cmdDeleteServerSapce.ExecuteNonQuery() within your loop. I would recommend the following:
cmdInsertServerSpace.Parameters.Add("#drive", SqlDbType.VarChar);
cmdDeleteServerSapce.Parameters.Add("#deletedrive", SqlDbType.VarChar);
for (int i = 0; i < driveStats.Length; i++) {
string temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters["#drive"].Value = temp;
cmdDeleteServerSapce.Parameters["#deletedrive"].Value = temp;
i++;
.....
cmdInsertServerSpace.ExecuteNonQuery();
cmdDeleteServerSapce.ExecuteNonQuery();
}
You must use parameter clear
**cmdInsertServerSpace.Parameters.Clear();**
cmdInsertServerSpace.Parameters.AddWithValue("#dt", temp);
temp = server.ToString();
cmdDeleteServerSapce.Parameters.AddWithValue("#serd", temp);
cmdInsertServerSpace.Parameters.AddWithValue("#ser", temp);

c# confusing on loop

MessageBox.Show(urls[m]);
of the code below it show 16 time like a,a,a,a,b,b,b,b,c,c,c,c,d,d,d,d how can i add 4 non duplicate to urls[m]. My code is purpose to swlwct url from data base to open on 4 different browser1 browser 2 .. but on browser show the same URL
namespace tabcontrolweb
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string MyConString = "SERVER=192.168.0.78;" +
"DATABASE=webboard;" +
"UID=aimja;" +
"PASSWORD=aimjawork;" +
"charset=utf8;";
MySqlConnection connection = new MySqlConnection(MyConString);
MySqlCommand command = connection.CreateCommand();
MySqlDataReader Reader;
command.CommandText = "SELECT urlwebboard FROM `listweb` WHERE `urlwebboard` IS NOT NULL AND ( `webbordkind` = 'เว็บท้องถิ่น' ) and `nourl`= 'n' order by province, amphore limit 4 ";
connection.Open();
Reader = command.ExecuteReader();
string[] urls = new string[4];
string thisrow = "";
string sumthisrow = "";
while (Reader.Read())
{
thisrow = "";
for (int i = 0; i < Reader.FieldCount; i++)
{
thisrow += Reader.GetValue(i).ToString();
System.IO.File.AppendAllText(#"C:\file.txt", thisrow + " " + Environment.NewLine);
sumthisrow = Reader.GetValue(i).ToString();
}
for (int m = 0; m < 4 ; m++)
{
urls[m] = sumthisrow;
MessageBox.Show(urls[m]);
}
webBrowser1.Navigate(new Uri(urls[0]));
webBrowser1.Dock = DockStyle.Fill;
webBrowser2.Navigate(new Uri(urls[1]));
webBrowser2.Dock = DockStyle.Fill;
webBrowser3.Navigate(new Uri(urls[2]));
webBrowser3.Dock = DockStyle.Fill;
webBrowser4.Navigate(new Uri(urls[3]));
webBrowser4.Dock = DockStyle.Fill;
}
connection.Close();
}
I can't understand this code:
for (int m = 0; m < 4 ; m++)
{
urls[m] = sumthisrow;
MessageBox.Show(urls[m]);
}
Why are you inserting in urls[m] the same value?
Bear in mind that in the previous loop the variable sumthisrow will keep only the last value just like:
sumthisrow = Reader.GetValue(Reader.FieldCount - 1).ToString();
EDIT: Also consider using a StringBuilder for creation of thisrow variable.
EDIT 2: Put your disposable objects into a using statement.

Categories