Load my combobox with the column names of my database table - c#

I am using the following method to load data from a database and fill into my combo box. For example if my database table is as follows:
Table Name: PERSONS
Person_Id Person_Name
1 Jason
2 Carl
The names Jason and Carl will be loaded into the combo box. This works fine. I am now looking to load my combo box only with the column names as in Person_ID, Person_Name. Is there a way I could modify my current method to do that? Please advice.
private void fillCombo(string query, string name, ComboBox c)
{
MySqlCommand cmdReader;
MySqlDataReader myReader;
try
{
cmdReader = new MySqlCommand(query, conn);
myReader = cmdReader.ExecuteReader();
while (myReader.Read())
{
string temp;
if (name != null)
{
temp = myReader.GetString(name);
if (!c.Items.Contains(temp))
{
c.Items.Add(temp);
}
}
}
myReader.Close();
}
catch (Exception e) { Console.WriteLine("Unable to load data from database"); }
}
public MainWindow()
{
InitializeComponent();
fillCombo("SELECT * FROM PERSONS;", "Person_Name", comboBox1);
}

You can get column names like this:
cmdReader = new MySqlCommand(query, conn);
myReader = cmdReader.ExecuteReader();
for(int index=0; index < reader.FieldCount; index++)
{
c.Items.Add(myReader.GetName(index));
}

You could use the GetSchemaTable() method on the MySqlDataReader:
private void fillCombo(string query, string name, ComboBox c)
{
MySqlCommand cmdReader;
MySqlDataReader myReader;
try
{
cmdReader = new MySqlCommand(query, conn);
myReader = cmdReader.ExecuteReader();
var table = myReader.GetSchemaTable();
foreach (DataColumn column in Table.Columns)
{
string s = column.ColumnName;
if (!c.Items.Contains(s))
{
c.Items.Add(s);
}
}
myReader.Close();
}
catch (Exception e) { Console.WriteLine("Unable to load data from database"); }
}

Related

How to delete row from database depending on what is selected within a combobox

private void DeleteClient_Load(object sender, EventArgs e)
{
try
{
connection = new SqlConnection(new DatabaseConnection().cnnString.ToString());
connection.Open();
}
catch (Exception exp)
{
MessageBox.Show(exp.Message, "Could not establish connection to the database.", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
cmd = new SqlCommand(new DatabaseAdd().addToComboBoxSE.ToString(), connection);
cmd.ExecuteNonQuery();
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(dt);
foreach(DataRow dr in dt.Rows)
{
comboBox1.Items.Add(dr["Id"] + ". " + dr["FirstName"] + " " + dr["Surname"]);
}
connection.Close();
}
Here i am adding items to a comboBox from a database. I am adding the ID(int), FirstName(varchar) and Surname(varchar) to each item for each row in the database.
My question is, how do i go about deleting a row from the database depending on a list item i have selected within the comboBox? I am able to do it when i just add the ID(int) to the comboBox but since i need the id, firstname and surname, i am unable to retrieve the ID from whatever list option i have selected.
Any help is appreciated. Thank you.
You need to create an instance of ComboBoxItem class and set its Value property to the id you want, then add it to your combobox.
The Class ComboBoxItem.cs:
public class ComboBoxItem
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Text;
}
}
Inside your foreach loop should be:
ComboBoxItem itm = new ComboBoxItem();
itm.Value = dr["Id"];
itm.Text = dr["Id"] + ". " + dr["FirstName"] + " " + dr["Surname"];
ComboBox1.Items.Add(itm);
You can get the selected item's id like this:
String selectedId = ((ComboBoxItem)(ComboBox1.SelectedItem)).Value.ToString();
Hope it helps.
Assuming that the Id is a numeric field, what you need to do is to split your string and extract the value of ID from the list. Since the format of the item is identical for all items, we can use the ". " as the separator string.
So, you can write something like this:
var str = selectedItem; // this is the value of selected item from the combo box and it's type is string. Example: "123. John Doe"
int ID = 0;
var str = selectedItem.Trim(); // this is the value of selected item from the combo box and it's type is string
var index = selectedItem.IndexOf(". ");
if (index > 1)
{
ID = Int32.Parse(selectedItem.Substring(0, index ) );
}
I was not sure
if you're asking to remove a row from the ComboBox once selected then
or delete from the db
This handles both, remove from Combo or delete from DB RowDeleter(string cmbName = "", bool deleteFromComboxBox )
Edit 1 updated the code based on comment:
//added optional parameter to pass combobox value after successfully record operations, or just call it
private void RowDeleter(ComboBox myComboBox)
{
try
{
SqlConnection conn = new SqlConnection(dataconnection);
SqlCommand cmd = new SqlCommand("myconn", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "yourtableset");
//look at what it is
String selectedId = (ComboBoxItem)(myComboBox.SelectedItem).Value.ToString();
DeleteRecord(selectedId);
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
// delete Helper
private void DeleteRecord(string row)
{
return if (StringIsNullOrEmpty(row))
string sql = "DELETE FROM Table1 WHERE RowID = #row";
SqlCommand deleteRecord = new SqlCommand();
deleteRecord.Connection = someconnection;
deleteRecord.CommandType = CommandType.Text;
deleteRecord.CommandText = sql;
SqlParameter RowParameter = new SqlParameter();
RowParameter.ParameterName = "#RowID";
RowParameter.SqlDbType = SqlDbType.string; //or int
RowParameter.IsNullable = false;
RowParameter.Value = row;
deleteRecord.Parameters.Add(RowParameter);
deleteRecord.Connection.Open();
deleteRecord.ExecuteNonQuery();
deleteRecord.Connection.Close();
booksDataset1.GetChanges();
// sqlDataAdapter1.Fill(someDataset.WHatverEmployees);
}

Delete all the data from the gridview

I want to implement a button on a web page which deletes all the data that has been shown on the gridview. Is there any simpler way to delete all data at once with the button?
It's very simple to do. Just iterate over each row in the gridview with and get the primary key value, then using the sql query to delete the record from the database.
The code here can help you. I am using the NorthWind sample database.
void loaddata()
{
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabaseConnectionString"].ConnectionString);
SqlCommand command = new SqlCommand();
connection.Open();
try
{
command = connection.CreateCommand();
command.CommandText = "SELECT * FROM Employees";
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataTable datatable = new DataTable();
adapter.Fill(datatable);
GridView1.DataSource = datatable;
}
catch (Exception)
{
throw;
}
finally
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
int employee_id;
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabaseConnectionString"].ConnectionString);
SqlCommand command = new SqlCommand();
connection.Open();
try
{
command = connection.CreateCommand();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
employee_id = Convert.ToInt32(GridView1.Rows[i].Cells[0].Text);
command.CommandText = "DELETE FROM Employees WHERE EmployeeID = '" + employee_id + "'";
command.ExecuteNonQuery();
}
}
catch (Exception)
{
throw;
}
finally
{
if (connection.State == ConnectionState.Open)
{
connection.Close();
}
}
loaddata();
}
You can always just set the DataSource to null.
someGridView.DataSource = null;
someGridView.DataBind();
I can only be as vague as the question and I still don't quite understand why I can't leave comments, but I can leave an answer...
Anyway, we don't know what you're using to access your database or the model backing the GridView.
Let's say for instance you have the following class backing your GridView (the type of data your GridView consists of that you've set the Datasource to):
public class MyData
{
public int ID { get; set; }
public string SomeData { get; set; }
}
In your ASPX you'd have the following:
<asp:GridView ID="GridView" runat="server"></asp:GridView>
<asp:Button ID="DeleteButton" runat="server" OnClick="DeleteButton_Click"/>
And then in your code-behind, you'd do something like this...
protected void DeleteButton_Click(object sender, EventArgs e)
{
var gridViewItemsToDelete = (IEnumerable<MyData>)GridView.DataSource;
foreach (var idToDelete in gridViewItemsToDelete.Select(r=>r.ID))
{
// Delete the item by its ID
// I don't know what you're using to access your database
}
// Save Changes if you didn't in the foreach loop...
}

IndexOutOfBoundsException when debugging foreach statement

//I've list out the codes below, pls take a look and i'd appreciate if i can get some help. My program which is throwing index out of bound exception at line String studadmin = admin[g];
protected void Button1_Click(object sender, EventArgs e)
{
//retrieve studentdetails using List<String[];
List<String[]> stud = new List<String[]>();
int i = 0;
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox check = (CheckBox)row.FindControl("CheckBox1");
if (check.Checked)
{
String [] studDetail = new String [1];
studDetail[0] = row.Cells[1].Text;
stud.Add(studDetail);
}
i++;
}
int g = 0;
foreach (String[] admin in stud)
{
String studadmin = admin[g];
// here's whr the error are prompted (IndexOutOfBoundsException),
// when it reads the following "admin", the loop just ends here with an error;
try
{
myConnection = db.getConnection();
SqlCommand cmd = new SqlCommand("sp_IPPLOAssign");
cmd.Connection = myConnection;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#AcadYear", lb_AcadYear.Text);
cmd.Parameters.AddWithValue("#AcadPeriod", lb_AcadPeriod.Text);
cmd.Parameters.AddWithValue("#IPPProjID", lb_ProjID.Text);
cmd.Parameters.AddWithValue("#ProjSubID", "0");
cmd.Parameters.AddWithValue("#LOLoginID", ddl_LO.SelectedValue);
cmd.Parameters.AddWithValue("#LoginID", Session["UserID"].ToString());
cmd.Parameters.AddWithValue("#Adminno", studadmin);
myConnection.Open();
cmd.ExecuteNonQuery();
lb_Msg.Text = "Update Success.";
lb_error.Text = "";
}
catch (Exception ex)
{
share.WriteLog(ex.Message, "LOAssign.aspx", "Button1_Click()", "Error in updating LO.");
lb_error.Text = "Update failed.";
lb_Msg.Text = "";
}
finally
{
if (myConnection.State == ConnectionState.Open)
myConnection.Close();
}
g++; //loop the subsequent studadmin and store into database
}
refresh_gvCompany();
refresh_gvCurrent(); //refresh gridview
}
Have you confirmed your parameter names are exactly correct? Should #Adminno be #AdminNo, perhaps?
Every item in your stud is an array of String of size 1.
However, at every iteration you are increasing the index of array:
String studadmin = admin[g];
// ...
g++; // loop the subsequent studadmin and store into database
As the result, you actually try to access stud[0][0], stud[1][1]... the errors occurs here, because stud[1] contains only one item.
You need to remove i and g - they are both useless.
As your array only contains one item, it actually looks like you misunderstand usage of List and array. Probably, you want a List<string> instead of List<string[]>:
protected void Button1_Click(object sender, EventArgs e)
{
List<string> stud = new List<string>();
foreach (GridViewRow row in GridView1.Rows)
{
CheckBox check = (CheckBox)row.FindControl("CheckBox1");
if (check.Checked)
{
stud.Add(row.Cells[1].Text);
}
}
foreach (string studadmin in stud)
{
try
{
myConnection = db.getConnection();
SqlCommand cmd = new SqlCommand("sp_IPPLOAssign");
cmd.Connection = myConnection;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#AcadYear", lb_AcadYear.Text);
cmd.Parameters.AddWithValue("#AcadPeriod", lb_AcadPeriod.Text);
cmd.Parameters.AddWithValue("#IPPProjID", lb_ProjID.Text);
cmd.Parameters.AddWithValue("#ProjSubID", "0");
cmd.Parameters.AddWithValue("#LOLoginID", ddl_LO.SelectedValue);
cmd.Parameters.AddWithValue("#LoginID", Session["UserID"].ToString());
cmd.Parameters.AddWithValue("#Adminno", studadmin);
myConnection.Open();
cmd.ExecuteNonQuery();
lb_Msg.Text = "Update Success.";
lb_error.Text = "";
}
catch (Exception ex)
{
share.WriteLog(ex.Message, "LOAssign.aspx", "Button1_Click()", "Error in updating LO.");
lb_error.Text = "Update failed.";
lb_Msg.Text = "";
}
finally
{
if (myConnection.State == ConnectionState.Open)
myConnection.Close();
}
}
refresh_gvCompany();
refresh_gvCurrent();
}

Multiple CheckedListBox and database connections

I'm loading a table from a database into a CheckedListBox, and now I need to check which items are checked any time the user changes the check status of an item in the first CheckedListBox, and then add the corresponding parts of another table from my database to the second CheckedListBox.
So for example, I have chlbMeal and chlbFood. Inside the chlbMeal there are "Breakfast", "Dinner" and "Lunch". Now when the user selects any of these, I want the corresponding food options to show up in the chlbFood - for example, if "Breakfast" is checked, inside chlbFood we have "Fried eggs", "Eggs and Bacon", etc.
My project is somewhat different but that's the main the idea I want to achieve in this part of it. Here is my code:
private void chlbRadovi_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
if (chlbRadovi.CheckedItems.Count > 0)
{
int[] niz = new int[chlbRadovi.CheckedIndices.Count];
chlbRadovi.CheckedIndices.CopyTo(niz, 0);
foreach (int x in niz)
{
this.tipradovaTableAdapter1.Fill(this.ignaDataSet1.tipradova);
SqlConnection con = new SqlConnection(Konekcija.con);
SqlCommand cmd = new SqlCommand("select IDTR, Naziv from tipradova where IDRad in #IDRad", con);
cmd.Parameters.AddWithValue("#IDRad", chlbRadovi.ValueMember[x]);
SqlDataReader reader;
chlbTipoviRadova.DataSource = ignaDataSet1.tipradova;
chlbTipoviRadova.DisplayMember = "Naziv";
chlbTipoviRadova.ValueMember = "IDTR";
con.Open();
reader = cmd.ExecuteReader();
con.Close();
}
}
else
{
chlbTipoviRadova.DataSource = null;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
How can I do this?
Ok, here we go. First, bind data to your first CheckedListbox:
private string connectionString = "Your connection string";
private void cbListFirst_SetDataSource()
{
// Using block will automatically close connection when it's not used anymore
using (var con = new SqlConnection(connectionString))
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"SELECT Id, Name
FROM dbo.FoodTypes";
try
{
con.Open();
var foodTypes = new List<FoodType>();
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Fill items for first CheckedListBox DataSource
while (reader.Read())
{
foodTypes.Add(new FoodType()
{
Id = (int)reader["Id"],
Name = reader["Name"] as string
});
}
}
// Set first CheckedListBox DataSource
cbListFirst.DataSource = foodTypes;
cbListFirst.DisplayMember = "Name";
cbListFirst.ValueMember = "Id";
}
catch (Exception ex)
{
// Clear DataSource and handle error (should be improved)
cbListFirst.DataSource = null;
MessageBox.Show("Error", ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
After you've done that, you should have ParentIds encapsulated inside your FoodType objects inside DataSource of your first CheckedListbox. Now, you shouldn't use SelectedIndexChanged event, but ItemCheck event instead. So every time user checks or unchecks one of the items event will be triggered. Only problem you have now is that inside this event, new CheckValue of clicked item is not yet applied, but it can be handled easy since we have information about new and old value inside EventArgs. Check this out:
private void cbListFirst_ItemCheck(object sender, ItemCheckEventArgs e)
{
// Clear second CheckedListbox DataSource
cbListSecond.DataSource = null;
var ingridients = new List<Ingridient>();
foreach (var item in cbListFirst.CheckedItems)
{
// If item was previously checked, we want to skip it because it's new value is
// unchecked and we shouldn't be adding it's child items to second CheckedListbox
if (cbListFirst.Items.IndexOf(item) != e.Index)
{
var foodType = (FoodType)item;
ingridients.AddRange(GetIngridientsForFoodType(foodType.Id));
}
}
// If item was previously unchecked, it's child items won't be caught in previous loop
// so we want to explicitly include them inside this if-block if new value is checked
if (e.NewValue == CheckState.Checked)
{
var foodType = (FoodType)cbListFirst.Items[e.Index];
ingridients.AddRange(GetIngridientsForFoodType(foodType.Id));
}
// Finally, bind new DataSource
cbListSecond.DataSource = ingridients;
cbListSecond.DisplayMember = "Name";
cbListSecond.ValueMember = "Id";
}
// This method returns list of Ingridients for single FoodType
private List<Ingridient> GetIngridientsForFoodType(int foodTypeId)
{
using (var con = new SqlConnection(connectionString))
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"SELECT Id, Name
FROM dbo.Ingridients
WHERE FoodTypeId = #FoodTypeId";
cmd.Parameters.AddWithValue("#FoodTypeId", foodTypeId);
try
{
con.Open();
var ingridients = new List<Ingridient>();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
ingridients.Add(new Ingridient()
{
Id = (int)reader["Id"],
Name = reader["Name"] as string
});
}
}
return ingridients;
}
catch (Exception ex)
{
// Handle error (should be improved) and return null
MessageBox.Show("Error", ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
}
Now your second CheckedListbox should be filled with child values of items from first CheckedListbox.

Stop duplicate TreeView Nodes

I have a table for Orders (orderTBL). When the user creates an order it adds a new row into the database with a custom order number. I load my treeview nodes from this database, however, if there is more than one row with the same order number, it creates more than one treeview node. Is it possible to display only one treeview node per order number? The TreeView is used to control a DataRowFilter to only display orders with the order number selected in a DataGridView This is the code I use :
public void ordersForm_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'lWADataBaseDataSet.orderTBL' table. You can move, or remove it, as needed.
// this.orderTBLTableAdapter.Fill(this.lWADataBaseDataSet.orderTBL);
getOrders();
getNumbers();
string sOrder = null;
int I = 0;
for (I = 0; (I <= (orderTBL.Rows.Count - 1)); I++)
{
sOrder = orderTBL.Rows[1][1].ToString();
treeView1.Nodes[0].Nodes.Add(sOrder);
}
}
private void getNumbers()
{
SqlCeConnection con = new SqlCeConnection(#"Data Source=|DataDirectory|\LWADataBase.sdf;");
try
{
con.Open();
}
catch (SqlCeException ex)
{
MessageBox.Show(ex.Message);
return;
}
treeView1.Nodes.Clear();
SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM orderTBL ORDER BY[Order Number] ASC", con);
try
{
SqlCeDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
TreeNode node = new TreeNode(dr["Order Number"].ToString());
treeView1.Nodes.Add(node);
}
}
catch (SqlCeException ex)
{
MessageBox.Show(ex.Message);
return;
}
con.Close();
}
I am assuming that having more than one row with the same order # is part of your design. If not you should do a check on the database before insertion.
Being part of your design you just want to load one node for each order you can do this in two ways.
Filter the data via the query:
SqlCeCommand cmd = new SqlCeCommand("SELECT distinct [Order Number] FROM orderTBL ORDER BY[Order Number] ASC", con);
'distinct' tells the database to make sure now row in the return set is duplicated.
Or maintain a temp list during load that checks if you have loaded that order yet.
private void getNumbers()
{
SqlCeConnection con = new SqlCeConnection(#"Data Source=|DataDirectory|\LWADataBase.sdf;");
try
{
con.Open();
}
catch (SqlCeException ex)
{
MessageBox.Show(ex.Message);
return;
}
treeView1.Nodes.Clear();
SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM orderTBL ORDER BY[Order Number] ASC", con);
try
{
//Temp List
List<string> ordersLoaded = new List<string>();
SqlCeDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string oderNum = dr["Order Number"].ToString();
//Check if you loaded that order already
if (!ordersLoaded.Contains(oderNum))
{
//Add order to loaded list
ordersLoaded.Add(oderNum);
treeView1.Nodes.Add(new TreeNode(oderNum));
}
}
}
catch (SqlCeException ex)
{
MessageBox.Show(ex.Message);
return;
}
con.Close();
}

Categories

Resources