Need a little bit of help finishing a generic MySQL select method - c#

General info
I'm busy writing my own MySQL database class inside C#. At the moment I'm trying to write a Select method that accepts a select query and returns a List with all the data. I'm still very new to C# so if my approach to this problem is wrong, please do not hesitate to tell me.
The problem
Right now my method expects 2 parameters. The query and the number of columns selected by the query. With that info I prepare my List and start filling it up. To do this I'm relying on the amount of columns with a foreach loop. However, I have no idea on how to get the correct column names
when adding to the List. Aside from that, I'm not sure if my approach is going to work. So I hope you guys would like to take a look at my method and help me out finishing it.
The method
public List<string>[] Select(string query, int items)
{
//Create a list to store the result
List<string>[] resultList = new List<string>[items];
for(int i = 0; i < items; i++)
{
resultList[i] = new List<string>();
}
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data and store them in the list
while (dataReader.Read())
{
for(int j = 0; j < items; j++)
{
resultList[j].Add(dataReader["columnName_here"] + "");
}
}
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
//return list to be displayed
return resultList;
}
else
{
return resultList;
}
}

MySqlDataReader is derived from System.Data.Common.DbDataReader, so you can use this code to get the columns:
for (int c = 0; c < dataReader.FieldCount; c++)
{
string name = dataReader.GetName(c);
Type type = dataReader.GetFieldType(c);
}

Related

Remove existing items in listbox from database

I am trying to delete the items within the listbox, which already exists in my database. My listbox is populated by a set of random names, and the ones that are equal to the data from the table rows should be deleted.
My code:
SqlCommand RemoveUserName = new SqlCommand("SELECT * FROM Name WHERE ([Name] = #check)", Con);
RemoveUserName.Parameters.AddWithValue("#check", listbox1.Items);
SqlDataReader dr = RemoveUserName.ExecuteReader();
if (dr.HasRows)
{
listBox1.Items.Remove(); // ?? Remove the names which are already in the database
}
else
{
// remain in listbox
}
Getting an error in my parameter value and I don't know how to delete the said items.
EDITED my current code:
SqlCommand RemoveUserName = new SqlCommand("SELECT * FROM Name", Con);
SqlDataReader dr = RemoveUserName.ExecuteReader();
while (!dr.Read())
{
for (int i = 0; i < listBox1.Items.Count; ++i)
{
if (listBox1.Items[i].ToString() == dr["Name"].ToString())
listBox1.Items.Remove(listBox1.Items[i]);
}
}
Has no error anymore, but is still not functional.
WORKING CODE:
for (int i = listBox1.Items.Count - 1; i >= 0; --i)
{
using (var cmd = new SqlCommand("UPDATE [Name] SET [Name] = Name WHERE [Name] = #name", Con))
{
cmd.Parameters.AddWithValue("#name", listBox1.Items[i].ToString());
if (cmd.ExecuteNonQuery() > 0)
{
listBox1.Items.RemoveAt(i);
}
}
}
Thanks # LarsTech
It helps to loop backwards through the list in order to avoid indexing issues:
for (int i = listBox1.Items.Count - 1; i >= 0; --i) {
using (var cmd = new SqlCommand("DELETE FROM [Name] WHERE [Name] = #name", Con)) {
cmd.Parameters.AddWithValue("#name", listBox1.Items[i].ToString());
if (cmd.ExecuteNonQuery() > 0) {
listBox1.Items.RemoveAt(i);
}
}
}
ExecuteNonQuery will return the number of records affected, so if it's greater than zero, the name was found and deleted.
Make sure to close your connection object, too. Best by putting it also in a using block the way the SqlCommand object is in my example.
Your table and column names need to be improved.
As I understood,
1) You need to delete items from listbox that already exists in your database and read by SqlDataReader.
You first need to loop into reader. So instead of !while(reader.Read()) use while(reader.Read())
2) Now you want to remove actual item from listbox, if it exists in reader.
So try to do following to remove item from listbox inside reader while loop
for (int n = listBox.Items.Count - 1; n >= 0; --n)
{
var removelistitem = dr["Name"].ToString();
if (listBox.Items[n].ToString().Contains(removelistitem))
{
listBox.Items.RemoveAt(n);
}
}
Now after while loop execution. your listbox will only have items not present in your reader (data from database).
Hope this helps.
Edit
Its ok to loop in listbox items.
Use RemoveAt instead. (See above answer)
try this:
while (!dr.Read())
{
for (int i=0; i<listBox1.Items.Count; ++i)
{
if (listBox1.Items[i].ToString() == dr["columnName"].ToString())
listBox1.Items.Remove(listBox1.Items[i]);
}
}
SqlReader must be read before use it. If there's no rows in the Reader, code in while block won't be executed.
EDIT I got a problem making you unhappy....
The code you provided:
RemoveUserName.Parameters.AddWithValue("#check", listbox1.Items);
Is wrong, because #check parameter expects string, but you provided was ObjectCollection. Revise query "SELECT * FROM Name WHERE ([Name] = #check)" to "SELECT * FROM Name". and remove the line AddWithValue.

How to populate list or array with values from access database

I am trying to populate a group of labels in a C# windows form with some values that are in a certain attribute (PlayerName) in a database that I have in access.
Currently the only code I have is:
OleDbConnection connection = new OleDbConnection(CONNECTION STRING HERE);
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
command.CommandText = "SELECT PlayerName FROM [TotalPlayerName] WHERE Team = 1 AND SportID = " + Form1.IDNumber;
I need a list or array that holds these values so I can use them to populate the labels, but I am unaware of how to do this.
You need to call ExecuteReader to obtain a data reader and then loop through the rows of the result set like this:
List<string> result = new List<string>();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
result.Add(reader.GetString(0));
}
}
Before you do this, don't forget to open the connection like this:
connection.Open();
There are a couple of things here..... for sake of best practice well its more standard practice... as I like to say!
Use USING as this cleans up after connection.. see here for great examples in a "using" block is a SqlConnection closed on return or exception?
using (OdbcDataReader DbReader = DbCommand.ExecuteReader())
{
int fCount = DbReader.FieldCount;
while (DbReader.Read())
{
Label1 = DbReader.GetString(0);
Label2 = DbReader.GetString(1);
Label3 = DbReader.GetString(2);
Label4 = DbReader.GetString(3);
for (int i = 0; i < fCount; i++)
{
String col = DbReader.GetString(i);
Console.Write(col + ":");
}
Console.WriteLine();
}
}
NB your SQL only return 1 field /String at the moment
while reading the data fill the list like
List<string> players = new List<string>();
OleDbDataReader rdr = command.ExecuteReader();
While(rdr.Read())
{
players.Add(rdr["PlayerName"].ToString());
}
You need to create a OleDbReader object to read the response from the query. You will also need to create a List to store the data Something like this:
List<string> playerNameList = new List<string>();
using (OleDbReader r = command.ExecuteReader())
{
while(reader.Read())
{
playerNameList.Add(reader.GetString(0));
}
}
One option might be using OleDbDataAdapter to fill a DataTable those values that returns your query;
var dt = new DataTable();
using(var da = new OleDbDataAdapter(command))
{
da.Fill(dt);
}
And since your query return one column, you can use AsEnumerable to that datatable to get them as a string like;
List<string> list = dt.AsEnumerable()
.Select(r => r.Field<string>("PlayerName"))
.ToList();
You can read: Queries in LINQ to DataSet
By the way, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Also use using statement to dispose your connection and command automatically as I did for OleDbDataAdapter in my example.

How can I add and get all my database table values (numbers) and displaying the total amount? C#

I am since recently struggling with a new problem. I've got a database table that contains multiple fields (columns) with a few rows containing (money - decimal) values that are related to the fieldnames.
For example:
table = money
Field names: Rent A, Rent B, Rent C
Values: $10, $20, $30.
What I want to do is getting these values from the database, add them together and displaying the total amount in a label.
Up till now I used the OleDbDataReader for all my outputting/storing value needs. Though I have absolutely no clue how I can add the read values since the reader usually expects an pre defined field name to read.
In my project however, a user can add a custom new field name (so a pre defined field name in the reader isn't possible because you don't know which custom field names will be added by the user in the DB. These custom added fields names and their values need to be added in the total amount as well though..
Does anyone have a clue how I can fix this?
I've tried multiple things like storing it in an array, defining decimal variables and using something like x = x + (decimal)reader[0] but this all didn't work so I think I am way off.
The code (and query) I am using for the reading part is as follows:
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from money where [Month]='January'";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//Something I tried
//x[0] = (decimal)reader[0];
//x[1] = (decimal)reader[1];
//And so on...
//Another thing I tried
//list.Add(reader.GetInt32(0));
}
//list.ToArray();
//int sum = list.Sum();
// y = x[0] + x[1] + ...;
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
You should just be able to declare a variable, then add up all the columns. If you don't know the number of columns in the reader, you can get that using reader.FieldCount.
You do not need to know the column name to get data from the reader. You can access it by column index as you started to do, e.g. reader[0], or using the helper methods such as GetDecimal(0).
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from money where [Month]='January'";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
// start the total at 0
int total = 0.0m;
while (reader.Read())
{
// loop through all the fields in the reader
for(int f = 0; f < reader.FieldCount; f++) {
// read as a decimal and add to the total
total += reader.GetDecimal(f);
}
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
Hope this helps -
decimal total = 0M;
while (dr.Read())
{
for (int i = 0; i < dr.FieldCount; i++)
{
total+= (decimal) (dr[i] != DBNull.Value ? dr[i] : 0.0);
}
}
this will add all the column's value for each row.
Datareader has property called field count which can give number of columns.. so you can use it something like below
double num=0.0m;
for (int i = 0; i < rdr.FieldCount; i++)
num += rdr[i];

Writing Sql Update method

public static int SQLUpdate(string sql, string[] names, object[] values)
{
if (names.Length != values.Length)
{
throw new ArgumentException("name/value mismatch");
}
using (var sqlconn = new SqlConnection(GetConnectionString))
{
sqlconn.Open();
using (var cmd = new SqlCommand(sql, sqlconn))
{
for (int i = 0; i < names.Length; i++)
{
cmd.Parameters.AddWithValue(names[i], values[i]);
}
return cmd.ExecuteNonQuery();
}
}
I wrote method to create Update command.
For example I have a Picture table in my SQL Server database with PictureID, UserID columns.
And user can add 3 pictures at once. You see values is array.
But in my example value[i] also is array. (3 pictures).
How can I write my SQLUpdate method for this ?
I think you are almost there except I would switch your code around a little so:
sqlconn.Open();
for (int i = 0; i < names.Length; i++)
{
using (var cmd = new SqlCommand(sql, sqlconn))
{
cmd.Parameters.AddWithValue(names[i], values[i]);
return cmd.ExecuteNonQuery();
}
}
**AS you are declaring a new SQLCommand everytime you may need to do cmd.Close() and cmd.Dispose() each time.
I think you need to pass data table in SQL procedure
http://www.codeproject.com/Tips/214492/Passing-a-datatable-to-a-stored-procedure-in-Sql-S

Arraylist of arraylist...in c#

I need to get data from a SQL query, I have a method that returns me an arraylist of arraylist, but I am not able to show me the data returned by the query sql.
I write the method returns the sql query:
public ArrayList ejecutarSelect(string sentenciaSQL){
if (this.conn.State != System.Data.ConnectionState.Open)this.Conectar();
ArrayList rows = new ArrayList();
MySqlCommand cmd = new MySqlCommand(sentenciaSQL, this.conn);
try
{
MySqlDataReader dataReader = cmd.ExecuteReader();
if (dataReader.HasRows)
{
while (dataReader.Read())
{
ArrayList row = new ArrayList();
for (int i = 0; i < dataReader.FieldCount; i++) row.Add(dataReader.GetString(i));
rows.Add(row);
}
}
dataReader.Close();
}
catch (Exception e)
{
CLog.log("ERROR (CDBMgr): " + e.Message);
return null;
}
return rows;
}
row.Add(dataReader[i].ToString());
See SqlDataReader.GetString Method.
It says
No conversions are performed; therefore, the data retrieved must already be a string.
So ..

Categories