I am trying to do an Ordering System where you can put many Products in one order. I have very little knowledge about this and this is where i am now
There are 3 tables, Product table,Order table and the Order-products table.
I really don't know if this is right as i am beginner especially on foreign keys.
What I want to achieve is you can order many products and put that products into one "OrderID" like this example in pic below.
This are my only codes. Sorry but i am really lost at this.
public Form1()
{
InitializeComponent();
fillCart();
}
private void fillCart()
{
dgvCart.ColumnCount = 3;
dgvCart.Columns[0].Name = "ProductID";
dgvCart.Columns[1].Name = "ProductName";
dgvCart.Columns[2].Name = "Quantity";
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
//dgvproducts
}
private void Form1_Load(object sender, EventArgs e)
{
crud.FillDataGrid("Select * from Products", ref dgvProducts);
crud.FillDataGrid("Select * from Orders", ref dgvOrder);
crud.FillDataGrid("Select * from Orderproducts", ref dgvOrderview);
lbldate.Text = DateTime.Now.ToShortDateString();
}
private void button2_Click(object sender, EventArgs e)
{
//button add to cart
addData(dgvProducts.CurrentRow.Cells[0].Value.ToString(), dgvProducts.CurrentRow.Cells[1].Value.ToString(), txtqty.Text);
}
private void addData(string p1, string p2, string p3)
{
String[] row = { p1, p2, p3 };
dgvCart.Rows.Add(row);
}
private void button1_Click(object sender, EventArgs e)
{
//button insert
}
Thank you very much and i hope someone can help me with my problem.
Method use for filling datagridview from SQLserver 2008:
public crud()
{
cnString = "Data Source=DESKTOP-MQKIBSK\\SQLEXPRESS;Initial Catalog=MARISCHELLdatabase;Integrated Security=True";
cn = new SqlConnection(cnString);
}
public void FillDataGrid(string sql, ref ns1.BunifuCustomDataGrid dg)
{
try
{
DataSet ds = new DataSet();
cn.Open();
cmd = new SqlCommand(sql, cn);
adptr = new SqlDataAdapter(cmd);
adptr.Fill(ds);
dg.DataSource = "";
dg.DataSource = ds.Tables[0];
}
catch (Exception e)
{
MessageBox.Show("" + e.Message);
}
cn.Close();
}
How Linq 2 SQL dataclasses look for me:
The code that goes with it:
//I have 2 columns in my dataGridView, Id 1st amount 2nd
//I added 3 items for testing
List<Tuple<int, int>> cart = new List<Tuple<int,int>>();
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value != null && row.Cells[1].Value != null)
{
cart.Add(new Tuple<int, int>(Convert.ToInt32(row.Cells[0].Value.ToString()),Convert.ToInt32(row.Cells[1].Value.ToString())));
//Now each list item will have .Item1 (productId) and .Item2 (amount)
}
}
using (DataClasses1DataContext dataContext = new DataClasses1DataContext())
{
//The tables you add in the dataContext are accessible by name
Order order = new Order();
dataContext.Orders.InsertOnSubmit(order);
dataContext.SubmitChanges(); // Submit once so we get an orderId
foreach (Tuple<int, int> product in cart)
{
OrderProduct orderProduct = new OrderProduct();
orderProduct.OrderId = order.OrderID;
orderProduct.ProductId = product.Item1;
orderProduct.Amount = product.Item2;
dataContext.OrderProducts.InsertOnSubmit(orderProduct);
}
dataContext.SubmitChanges();
}
Create foreign key relationship between Order - OrderProduct over OrderID and Product - OrderProduct over Product ID.
For each Product in order insert a row into OrderProduct with OrderId
This may not answer your question completely but consider an object orientated approach to this. It's always better in my opinion to have a strongly typed method of accessing values returned from a database, although others may disagree. Here is some pseudo code to get you started and is by no means the entire solution but should encourage you to think how you can make your code more object orientated and strongly typed. Use the same methodology to save and update tables in your database.
example
//Business layer
public class Product
{
public string ProductName {get;set;}
public int Quantity {get;set;}
public string Unit {get;set;}
public decimal Price {get;set;}
public long Total {get;set;}
public Product(){}
public Product(string productName, int quantity, string unit, decimal price, long total)
{
ProductName = productName;
Quantity = quantity;
Unit = unit;
Price = price;
Total = total;
}
public List<Product> GetProductList()
{
//get the list of products from the data access layer
ProductDal dal = new ProductDal();
return dal.GetProductList();
}
}
//Data layer
public class ProductDal
{
public List<Product> GetProductList()
{
List<Product> lstProducts = new List<Product>();
//connect to your database code here
//fill your list with records from your Sql query
//inside your DataReader while loop you can add a new Product object to your list for each record
//assuming your database field names match the Product class's proeprties you would do this
lstProducts.Add(new Product((string)reader["ProductName"],
(int)reader["Quantity"],
(string)reader["Unit"],
decimal)reader["Price"],
(long)reader["Total"]));
return lstProducts;
}
}
//front end code behind page
private void button2_Click(object sender, EventArgs e)
{
Product product = new Product();
dgvCart.DataScource = product.GetProductList();
dgvCart.DataBind();
}
Related
I made a form that contains a datagridview, button, and a chart. The datagridview shows a Sales record of the business. The graph shows the top selling items from the datagridview. It is based from the quantity column (number of items sold) of the datagridview. What I want to happen is that when a user clicks the Generate button, a messagebox/ new form will appear.
It will contain a label (Top 3 Items) and under that label, there will be a ranking of the best selling items.
The question is how will I be able to create a ranking list in a messagebox/new form if the data is from a chart/datagridview?
Here's my current code for the form:
public partial class CFReport : Form
{
public CFReport()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
label5.Text = DateTime.Now.ToLongTimeString();
timer1.Start();
}
private void CFReport_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'casaFrancaDataSet.Sales' table. You can move, or remove it, as needed.
this.salesTableAdapter.Fill(this.casaFrancaDataSet.Sales);
timer1.Start();
label5.Text = DateTime.Now.ToLongTimeString();
label6.Text = DateTime.Now.ToLongDateString();
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Top 3 items:" + Environment.NewLine + "1. " + Environment.NewLine + "2. " + Environment.NewLine + "3. ");
}
}
Try this if I got the question right. You can use LINQ for ordering your chart/datagridview.
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApp9
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
List<Product> products = new List<Product>(); // your chart/datagridview
products.Add(new Product { Name = "Banana", Price = 1 });
products.Add(new Product { Name = "Orange", Price = 10 });
products.Add(new Product { Name = "Apple", Price = 5 }); // your products
products = products.OrderByDescending(p => p.Price).ToList(); // ordering products by price
StringBuilder sb = new StringBuilder();
int i = 1;
foreach (var product in products)
{
sb.Append($"{i}. {product.Name} - {product.Price}\n");
i++;
}
MessageBox.Show(sb.ToString());
}
}
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
}
Use data binding to separate your data (model) from how the data is displayed (view).
Your DataGridView has a DataSource. Use that to show the data.
class DisplayedProduct
{
public int Id {get; set;}
public string Name {get; set;}
public int Quantity {get; set;}
public decimal Price {get; set;}
}
Use visual studio designer to create the columns and tell which column should show which property, or do this programmatically.
public MyForm : Form
{
public MyForm()
{
this.InitializeComponent();
this.columnId.DataPropertyName = nameof(DisplayedProdut.Id);
this.columnName.DataPropertyName = nameof(DislayedProduct.Name);
...
}
I'll make a lot of small methods, so they will be easy to understand, easy to reuse, easy to unit test, debug and change:
Fetch the Products:
private IEnumerable<DisplayedProduct> FetchProductsToDisplay()
{
... // TODO: implement
}
Create a property to show the Products and fetch the displayed (and possibly edited) products:
private BindingList<DisplayedProduct> DisplayedProducts
{
get => (BindingList<DisplayedProduct>)this.dataGridView1.DataSource;
set => this.dataGridView1.DataSource = value;
}
And show the products on form loading:
private void InitProductDisplay()
{
this.DisplayedProducts = new BindingList<DisplayedProduct>
this.FetchProductsToDisplay.ToList());
}
private void OnFormLoading(object sender, ...)
{
this.InitProductDisplay();
}
This is enough to show the products, and fetch them when needed. All changes made by the operator (add / remove rows, edit cells) are automatically reflected in the binding list.
private IEnumerable<DisplayedProduct> GetTopProducts()
{
return this.DisplayedProduts.OrderByDescending(product => product.Quantity);
}
private string CreateTextTopProducts(int count)
{
IEnumerable<DisplayedProduct> top3Products = GetTopProducts()
.Select((product, index) => new
{
Index = index + 1,
// select the properties that you want to show in the messagebox:
Name = product.Name,
...
})
.Take(count);
// use a string builder to efficiently add formatted lines:
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Top 3 items:");
foreach (var product in top3Products)
{
stringBuilder.AppendFormat("{0}. {1}", product.Index, product.Name);
stringBuilder.AppendLine();
}
return stringBuilder.ToString();
}
Finally the methods to show the top3 products:
private void ShowTop3Products()
{
string displayText = this.CreateTextTop3Products(3);
MessageBox.Show(this, displayText, ...);
}
private void button2_Click(object sender, EventArgs e)
{
this.ShowTop3Products();
}
I have a Database which has a table name CourseOffered that looks like this:
enter image description here
The only column i want to select (request to be returned) is Semester and add it to a dropdown list. Here's my code in the Repository Class.
public List<CoursesOffered> GetSemester()
{
List<CoursesOffered> SemestersName = null;
try
{
string sql = "SELECT DISTINCT Semester FROM CoursesOffered";
DataTable dt = _idac.GetManyRowsCols(sql, null);
SemestersName = DBList.ToList<CoursesOffered>(dt);
}
catch (Exception)
{
throw;
}
return SemestersName;
}
I'm calling GetManyRowsCols() from my DataAccess Class and I have a DBList and Entity Class that looks like this.
class DBList
{
public static List<T> ToList<T>(DataTable dt)
where T : IEntity, new()
{
List<T> TList = new List<T>();
foreach (DataRow dr in dt.Rows)
{
T tp = new T();
tp.SetFields(dr);
TList.Add(tp);
}
return TList;
}
}
public class EntityBase : IEntity
{
public void SetFields(DataRow dr)
{
// use reflection to set the fields from DataRow
Type tp = this.GetType();
foreach (PropertyInfo pi in tp.GetProperties())
{
if (null != pi && pi.CanWrite)
{
string nm = pi.PropertyType.Name.ToUpper();
if (nm.IndexOf("ENTITY") >= 0)
// In LINQ to SQL Classes, last properties are links to other tables
break;
if (pi.PropertyType.Name.ToUpper() != "BINARY")
pi.SetValue(this, dr[pi.Name], null);
}
}
}
}
This is how i'm trying to add it to the Drop down List,
private void CourseManagement_Load_1(object sender, EventArgs e)
{
try
{
List<CoursesOffered> semesterList = _ibusinessSemester.GetSemester();
cbCourseNumberDropDown.DataSource = semesterList;
cbCourseNumberDropDown.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
but i keep getting an error that says Column 'CourseNum' Does not belong to the table
Based on your description, you want to convert one column to list.
Since I don't have the code about IEntity, I can not test your code.
However, I make the following code to make it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var list = DBList.ToList<string>(table, "Semeter").Distinct().ToList();// the code I have modified
comboBox1.DataSource = list;
}
DataTable table = new DataTable();
private void Form1_Load(object sender, EventArgs e)
{
table.Columns.Add("Course",typeof(string));
table.Columns.Add("Semeter", typeof(string));
table.Columns.Add("MaxEncrollment", typeof(int));
table.Rows.Add("CPSC 410","Fall 2016",35);
table.Rows.Add("CPSC 411", "Fall 2016", 30);
table.Rows.Add("CPSC 440", "Fall 2016", 35);
table.Rows.Add("Math301", "Fall 2016", 35);
}
}
class DBList
{
public static List<T> ToList<T>(DataTable dt,string columnname)
{
List<T> TList = new List<T>();
TList = dt.AsEnumerable().Select(r => r.Field<T>(columnname)).ToList();
return TList;
}
}
In my project I wanted to read data from a file and update the DataGridView to a simple List. I wanted this so that the list can be updated at run time and then upon save wanted the final content of the list to be updated to a file.
In most of the solutions seen on google search I came up with examples of how to use a DatagridView with Database connection used to update the DatagridView. for Insert, Update and Delete operations. Lot of suggestions for my answer included adding INotifyProperty and IBindingList based impelementations which are probably an overkill.
I only aim to post my solution which involves using Datagridview to update a list. The code snippet used here is part of a huge project where updating the data from Datagridview to the List and back was a very big challenge due to initial impelementation with Database, whose dependency needed to be removed.
At the point of posting this question, I have a solution to my problem. To arrive at this problem I have taken bits and pieces of suggestions from various previous questions. I am not looking for suggestions in comments. If anyone wants to show me better way to solve this problem, please post an answer with working code.
So after reading, you have a sequence of MyData objects. You want to display all MyData objects (or a subsection) in a DataGridView.
Operators may change the displayed values, add some new rows, or delete rows. Some columns may be readonly and can't be changed
After pressing the OK-button, you want to read all MyData objects from the DataGridView and Save them in a file.
Most of your work can be done using the forms designer.
Open your form class in the designer
Drag a DataGridView on this form
Drag a BindingSource on this form
Right click BindingSource and select properties
Click in the properties window in DataSource on the arrow on the right
If MyData is not visible there, select Add Project Data Source
In the new window select object
Select the added data source as DataSource of your BindingSource
In the properties of DataGridView, assign your bindingSource to the DataSource
And suddenly: your DataGridView has the columns of the public properties of MyData. And magically, the columns have the correct type. They are able to display the values. Readonly properties have readonly Columns, read-write properties are editable.
To display your data:
void FillDataGridView(IEnumerable<MyData> dataToDisplay)
{
this.bindingSource1.DataSource = new BindingList<MyData>(dataToDisplay.ToList();
}
To read all data after editing
IEnumerable<MyData> ReadDataGridView()
{
return this.bindingSource1.List.Cast<MyData>();
}
This enables the operator to add and delete rows and to edit the values.
If you don't want the operator to do this, adjust the DataGridView properties
If the displayed values of the columns are not to your liking, edit the column properties (different header text, different display format, different backgroundcolor etc)
Here is an example where I have used the DatagridView to perform Insert Update and Delete on a List (List of Class objects PersonState).
The DatagridView’s Datasource needs to contain a DataTable, to bridge this gap, I have used a function named ConvertToDatatable().
As my starting point I began with a project suggested on another link by Anup Kumar Sharma.
Using the following code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;
namespace InsertUpdateDelete {
public partial class Form1 : Form {
public class PersonState {
public string Name { get; set; }
public string State { get; set; }
}
public List<PersonState> listOfPersonState;
public Form1() {
InitializeComponent();
listOfPersonState = new List<PersonState>();
}
//Display Data in DataGridView
private void DisplayData() {
DataTable dt = new DataTable();
dt = ConvertToDatatable();
dataGridView1.DataSource = dt;
}
//Clear Data
private void ClearData() {
txt_Name.Text = "";
txt_State.Text = "";
}
public DataTable ConvertToDatatable() {
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("State");
foreach (var item in listOfPersonState) {
var row = dt.NewRow();
row["Name"] = item.Name;
row["State"] = item.State;
dt.Rows.Add(row);
}
return dt;
}
private void AddToList(string text1, string text2) {
listOfPersonState.Add(new PersonState { Name = text1, State = text2 });
}
private void UpdateToList(string text1, string text2) {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState[index] = new PersonState { Name = text1, State = text2 };
}
private void DeleteToList() {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState.RemoveAt(index);
}
private void btn_Insert_Click(object sender, EventArgs e) {
if (txt_Name.Text != "" && txt_State.Text != "") {
AddToList(txt_Name.Text, txt_State.Text);
//MessageBox.Show("Record Inserted Successfully");
DisplayData();
ClearData();
} else {
MessageBox.Show("Please Provide Details!");
}
}
private void btn_Update_Click(object sender, EventArgs e) {
if (txt_Name.Text != "" && txt_State.Text != "") {
if (dataGridView1.SelectedRows != null && dataGridView1.SelectedRows.Count > 0) {
UpdateToList(txt_Name.Text, txt_State.Text);
//MessageBox.Show("Record Updated Successfully");
DisplayData();
ClearData();
}
} else {
MessageBox.Show("Please Select Record to Update");
}
}
private void btn_Delete_Click(object sender, EventArgs e) {
if (dataGridView1.SelectedRows != null && dataGridView1.SelectedRows.Count > 0) {
DeleteToList();
//MessageBox.Show("Record Deleted Successfully!");
DisplayData();
ClearData();
} else {
MessageBox.Show("Please Select Record to Delete");
}
}
private void dataGridView1_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
FillInputControls(e.RowIndex);
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) {
FillInputControls(e.RowIndex);
}
private void FillInputControls(int Index) {
if (Index > -1) {
txt_Name.Text = dataGridView1.Rows[Index].Cells[0].Value.ToString();
txt_State.Text = dataGridView1.Rows[Index].Cells[1].Value.ToString();
}
}
}
}
Learnings:
Observe that I have used propertis in the class.
Instead of using:
public class PersonState {
public string Name;
public string State;
}
I have used:
public class PersonState {
public string Name { get; set; }
public string State { get; set; }
}
For some reason, the former does not work when trying to assing values.
I have made the list of objects a class variable so that all
functions can access that list directly instead of it being passed
around as a parameter.
public List<PersonState> listOfPersonState;
I replaced the logic to Insert, Update and Delete to a DB, to Insert
Update and Delete to a List.
private void AddToList(string text1, string text2) {
listOfPersonState.Add(new PersonState { Name = text1, State = text2 });
}
private void UpdateToList(string text1, string text2) {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState[index] = new PersonState { Name = text1, State = text2 };
}
private void DeleteToList() {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState.RemoveAt(index);
}
Note: I am assigning the Grid directly from the List, so my Grid and my List always have the same index because I am using the Display function to ensure this on Insert, update and delete Button operations.
private void DisplayData() {
DataTable dt = new DataTable();
dt = ConvertToDatatable();
dataGridView1.DataSource = dt;
}
public DataTable ConvertToDatatable() {
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("State");
foreach (var item in listOfPersonState) {
var row = dt.NewRow();
row["Name"] = item.Name;
row["State"] = item.State;
dt.Rows.Add(row);
}
return dt;
}
I have a simple database with 2 tables (product and category) and the code below is to create a new product in the product table under one of the categories selected in the combo box.
public partial class frmAddProduct : Form
{
public frmAddProduct()
{
InitializeComponent();
db = new DatabaseEntities();
}
DatabaseEntities db;
string category = "";
Product _product;
private void frmAddProduct_Load(object sender, EventArgs e)
{
categoryBindingSource.DataSource = db.Categories.ToList();
CategoryList();
}
private void CategoryList()
{
var list = db.Categories.ToList();
cboCategory.DataSource = list;
cboCategory.DisplayMember = "CategoryName";
cboCategory.ValueMember = "CategoryID";
if (cboCategory.Items.Count > 1)
cboCategory.SelectedIndex = -1;
}
private void btnNew_Click_1(object sender, EventArgs e)
{
_product = new Product();
int id = int.Parse(txtID.Text);
decimal price = decimal.Parse(txtPrice.Text);
int qty = int.Parse(txtPrice.Text);
_product.ProductID = id;
_product.ProductName = txtName.Text;
_product.UnitPrice = price;
_product.UnitsInStock = qty;
_product.CategoryID = int.Parse(category);
db.Products.Add(_product);
db.SaveChanges();
}
private void cboCategory_SelectedIndexChanged(object sender, EventArgs e)
{
category = cboCategory.SelectedValue.ToString();
}
}
When I run the form an error appears saying "Additional information: Object reference not set to an instance of an object". The error refers to the next line in the code:
category = cboCategory.SelectedValue.ToString();
Does anyone know what is the problem here?
One note: CategoryID is an integer field in the database.
It looks like your setting of the SelectedIndex to -1 is triggering SelectedIndexChanged event with nothing in SelectedValue which you are trying to read in the handler. You might be missing check for null in the handler.
I have a class named Result which has 4 fields as id, marks, total, avg. I created the List class and stored the result.
Now I want to display only 2 columns in the datagrid. They are id and total. I successfully displayed the id and total but the datagrid shows 4 columns instead of 2. The columns are id, total, id, total
Here is my code to display the datagrid:
private void Form1_Load(object sender, EventArgs e)
{
List<Result> result = new List<Result>();
PopulateResult();
dgresult.AutoGenerateColumns = false;
dgresult.Items.Clear();
dgresult.ItemsSource = result;
DataGridTextColumn col1 = new DataGridTextColumn();
col1.Header = "Id";
col1.Binding = new Binding("Id");
DataGridTextColumn col2 = new DataGridTextColumn();
col2.Header = "Total";
col2.Binding = new Binding("Total");
dgresult.Columns.Add(col1);
dgresult.Columns.Add(col2);
}
}
class Result
{
int id;
int total;
int marks;
int avg;
public int Id { get { return id; } set { id = value; } }
public int Total { get { return total; } set { total = value; } }
public int Marks { get { return marks; } set { marks = value; } }
public int Avg { get { return avg; } set { avg = value; } }
public Result(int ID, int TOTAL, int MARKS, int AVG)
{
id = ID;
total = TOTAL;
marks = MARKS;
avg = AVG;
}
}
I don't understand why it is happening like this.
Thanks in advance.
I've added comments to your code that show my thoughts:
private void Form1_Load(object sender, EventArgs e)
{
// Make a new list of result class objects, local to the Form1_Load method:
List<Result> result = new List<Result>();
// Call a method that populates a list... wait, what list?
PopulateResult();
dgresult.AutoGenerateColumns = false;
dgresult.Items.Clear();
// Set the datagrid data source to the list created earlier
dgresult.ItemsSource = result;
// ...
I'm not sure why the datagrid has a duplicate set of columns after you've specified and added only two columns. It would help to see the method PopulateResult().
The list that PopulateResult() is adding to must be some other list, because the one created in Form1_Load is local in scope.
I'm not sure if this is just a little oversight, or if you need to learn about variable scope. Forgive me if this is already known to you:
C# Variable Scopes