Delete row in DataGridView and database - c#

I'm completely new to databases and EF but I made a database with EF and have a DataGridView control on a windows form that I made by dragging my datasource to my form. After the user enters their information and hits the save button it succesfully saves their information in the database using this code
public partial class bsMainPage : Form
{
BSDATAContainer db = new BSDATAContainer();
public bsMainPage()
{
InitializeComponent();
}
private void saveBtn_Click(object sender, EventArgs e)
{
BSRecords breakfastRecord = new BSRecords();
breakfastRecord.BS = brkBS.ToString();
breakfastRecord.Carbs = brkCarb.ToString();
breakfastRecord.Notes = brkftNoteTxt.Text;
breakfastRecord.Date = dateTxt.Text;
BSRecords lunchRecord = new BSRecords();
lunchRecord.BS = lchBS.ToString();
lunchRecord.Carbs = lchCarb.ToString();
lunchRecord.Notes = lnchNoteTxt.Text;
lunchRecord.Date = dateTxt.Text;
BSRecords dinnerRecord = new BSRecords();
dinnerRecord.BS = dnrBS.ToString();
dinnerRecord.Carbs = dnrCarb.ToString();
dinnerRecord.Notes = dnnrNoteTxt.Text;
dinnerRecord.Date = dateTxt.Text;
db.BSRecords.Add(breakfastRecord);
db.BSRecords.Add(lunchRecord);
db.BSRecords.Add(dinnerRecord);
db.SaveChanges();
}
}
But it doesn't show up in the database until I restart the program. When the user selects a row in the DataGridView and hits the delete button which has this code
private void deleteRowsBtn_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow item in this.bSRecordsDataGridView.SelectedRows)
{
bSRecordsDataGridView.Rows.RemoveAt(item.Index);
}
db.SaveChanges();
}
It deletes the data in the DataGridView but doesn't save the changes in my database. I have followed all the answers I found on here and other sites to delete in the database but nothing will save the deleted changes. Does anyone have any idea how to make it work?

You can delete it using remove. You will need to get the key/id field so without seeing the grid and assuming it is say in a hidden first column:
private void deleteRowsBtn_Click(object sender, EventArgs e)
{
string delId;
BSRecords deleteRecord;
foreach (DataGridViewRow item in this.bSRecordsDataGridView.SelectedRows)
{
bSRecordsDataGridView.Rows.RemoveAt(item.Index);
// code to remove record from database
delId = item.Cells[0].Value.ToString(); // column that has id field
deleteRecord = db.BSRecords.First(b => b.Id == delId); // get the record. will throw exception if not found.
db.BSRecords.Remove(deleteRecord);
}
db.SaveChanges();
bSRecordsDataGridView.DataBind(); // this will refresh your grid. Do same in save.
}
Also note you can rewrite this code:
BSRecords breakfastRecord = new BSRecords();
breakfastRecord.BS = brkBS.ToString();
breakfastRecord.Carbs = brkCarb.ToString();
breakfastRecord.Notes = brkftNoteTxt.Text;
breakfastRecord.Date = dateTxt.Text;
with an object initializer:
BSRecords breakfastRecord = new BSRecords { BS = brkBS.ToString(),
Carbs = brkCarb.ToString(),
Notes = brkftNoteTxt.Text,
Date = dateTxt.Text };

Related

How to move row from one table to another with no FK connection

I am doing Entity Framework and I have a database where there is no connection between the two tables. My form has two datagridviews each showing the contents of those tables on load. I also have two buttons. When I select any cell (which selects the entire row) on the sport table and click copy, it moves the data to the health table and removes it from the sport one. The second button does vice versa. What do you think is wrong?
I have tried delete and add and there seems to be a validation error. How can I fix this?
public partial class Form1 : Form
{
SportsAreUsEntities mySports = new SportsAreUsEntities();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
RefreshGrids();
}
private void RefreshGrids()
{
var allSport = from eachSport in mySports.SportingItems
orderby eachSport.SportingItemID ascending
select new
{
eachSport.SportingItemID,
eachSport.Name,
eachSport.Description,
eachSport.QuantityOnHand
};
dataGridSport.DataSource = allSport.ToList();
var allHealth = from eachHealth in mySports.HealthItems
orderby eachHealth.HealthItemID ascending
select new
{
eachHealth.HealthItemID,
eachHealth.Name,
eachHealth.Description,
eachHealth.QuantityOnHand
};
dataGridHealth.DataSource = allHealth.ToList();
}
private void moveToHealth_Click(object sender, EventArgs e)
{
//Retrieve selected row and id
var selectedRow = dataGridSport.CurrentRow;
int selectedID = (int)selectedRow.Cells["SportingItemID"].Value;
var data2 = new HealthItem();
var rowToDelete = (from row in mySports.SportingItems
where row.SportingItemID == selectedID
select row).Single();
var rowToAdd = (from row in mySports.SportingItems
where row.SportingItemID == selectedID
select row).Single();
mySports.SportingItems.Remove(rowToDelete); //Mark for deletion
mySports.HealthItems.Add(data2);
mySports.SaveChanges();
RefreshGrids();
}

How to edit/add/update datagridview directly on Windows Forms App

I am making a Windows Forms App that manages a hotel. It has Client, Room, Occupancy classes. Client and Rooms have an ArrayList that is populated at runtime from a .txt file that is then displayed in a clientListView and a roomDataGridView.
As such, I have this line of code to populate the roomsDGV:
roomsDGV.DataSource = roomsArrayList;
With the roomsDGV, I'm trying to add new Rows by clicking on the roomsDGV, like when it is NOT databound. I am also trying to edit the rows and save it to txt file after editing or as I'm editing. I can post more code as necessary but I'm not sure if showing more code will help at the current moment. In the end, I'm trying for a functionality so that I can highlight a client in the list and click on one of the rows in roomsDGV and assign that clientID to that room or any sort of way like that.
On load, the datagridview is loaded and formatted correctly from the arrayList but I seem to be having this problem of being able to edit the datagridview. It gives me this error when I click on one of the rows:
System.IndexOutOfRangeException: 'Index -1 does not have a value.'
This stems from Application.Run(new HotelManager());
Here is the form:
public partial class HotelManager : Form
{
// VARIABLES
string clientID;
// FILEPATHS
string clientsTxt = "Clients.txt";
string occupanciesTxt = "Occupancies.txt";
string roomsTxt = "Rooms.txt";
string clientsDat = "Clients.dat";
// ARRAYLIST FOR ROOMS and CLIENTS
ArrayList roomsArrayList = new ArrayList();
ArrayList clientsArrayList = new ArrayList();
//STACKS AND QUEUES INIT
// Load occupancies into stack > pop
Stack roomStack = new Stack();
Queue vacancyQueue = new Queue();
// RANDOM for ID
private readonly Random rand = new Random();
public HotelManager()
{
InitializeComponent();
}
private void HotelManager_Load(object sender, EventArgs e)
{
roomsDGV.DataSource = roomsArrayList;
// LOAD clients
// LoadClients();
RefreshClientList();
// LOAD rooms
LoadRooms();
}
private void NewClientButton_Click(object sender, EventArgs e)
{
AddClient();
}
private void checkInButton_Click(object sender, EventArgs e)
{
string clientID = clientList.SelectedItems[0].Text;
string[] text = File.ReadAllLines(occupanciesTxt);
foreach (string s in text)
{
if (s.Contains(clientID))
{
var replace = s;
Console.WriteLine(s);
replace = replace.Replace("false", "true");
}
}
File.WriteAllLines(occupanciesTxt, text);
}
// METHODS
private void AddClient()
{
//COLLECT DATA > CREATE NEW client > SHOW IN **PROGRAM/DataGridView** > add to clients file
// ID GENERATION > CHECKS AGAINST clientsTXT
clientID = rand.Next(0, 999999).ToString();
if (File.ReadLines(clientsTxt).Contains(clientID))
{
clientID = rand.Next(0, 999999).ToString();
}
Client client = new Client(clientID, firstNameBox.Text, lastNameBox.Text);
try
{
if (!string.IsNullOrWhiteSpace(phoneNumBox.Text))
{
client.PhoneNumber = Convert.ToInt64(phoneNumBox.Text);
}
if (!string.IsNullOrWhiteSpace(addressBox.Text))
{
client.Address = addressBox.Text;
}
}
catch (Exception)
{
MessageBox.Show("Please use the correct format!");
throw;
}
clientsArrayList.Add(client);
using (StreamWriter file =
new StreamWriter("Clients.txt", true))
{
file.WriteLine(client.ToString());
}
RefreshClientList();
// TEST CODE // SERIALIZATION TO .DAT
SerializeClientData(client);
}
private void LoadClients()
{
// LOADS arrayList FROM .txt FILE
List<string> clientList = File.ReadAllLines(clientsTxt).ToList();
foreach (var c in clientList)
{
Client client = new Client(c);
clientsArrayList.Add(client);
}
}
private void LoadRooms()
{
List<string> roomsList = File.ReadAllLines(roomsTxt).ToList();
foreach (var r in roomsList)
{
var roomDetails = r.Split('|');
if (r.Contains("BASIC"))
{
BasicRoom basic = new BasicRoom();
basic.RoomNumber = roomDetails[0];
basic.NumberOfBeds = Convert.ToInt32(roomDetails[1]);
basic.Balcony = Convert.ToBoolean(roomDetails[2]);
basic.DownForRepair = Convert.ToBoolean(roomDetails[3]);
basic.Smoking = Convert.ToBoolean(roomDetails[4]);
roomsArrayList.Add(basic);
}
else if (r.Contains("SUITE"))
{
Suite suite = new Suite();
suite.RoomNumber = roomDetails[0];
suite.NumberOfBeds = Convert.ToInt32(roomDetails[1]);
suite.Balcony = Convert.ToBoolean(roomDetails[2]);
suite.DownForRepair = Convert.ToBoolean(roomDetails[3]);
suite.NumberOfRooms = Convert.ToInt32(roomDetails[4]);
roomsArrayList.Add(suite);
}
}
roomStack = new Stack(roomsArrayList);
foreach (var item in roomStack)
{
Console.WriteLine(item);
}
}
private void RoomsDGV_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void RoomsDGV_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
}
}
So far I've looked through all the properties but I can't seem to find the right one. I know I can add/use comboboxes and etc to add a new item into the arrayList instead but I'm trying for datagridview functionality
I expect to edit and add rows to the DGV, but something in the designer is preventing me?
Here is the DGV, and clicking on any of the rows breaks it.
https://imgur.com/a/GG7ZwdV
check this
Insert, Update, Delete with DataGridView Control in C# (Windows Application) | A Rahim Khan's Blog
Insert, Update and Delete Records in a C# DataGridView
Good Luck

EF6 Context lost when using subset

Hi I have a Table 'Suppliers' and another 'SupplierPlants' I have both tables bound to DataGridViews via code:
bsSuppliers = new BindingSource();
bsSuppliers.DataSource = AppData.Suppliers;
bsSuppliers.AllowNew = true;
dgvSuppliers.DataSource = bsSuppliers;
dgvSuppliers.Refresh();
bsSuppliersPlants = new BindingSource();
bsSuppliersPlants.DataSource = AppData.SupplierPlants;
bsSuppliersPlants.AllowNew = true;
dgvSupplierPlants.DataSource = bsSuppliersPlants;
dgvSupplierPlants.Refresh();
The AppData class holds all of my DB entities:
Db = new PureTrialEntities();
Db.Suppliers.Load();
Suppliers = Db.Suppliers.Local;
Db.SupplierPlants.Load();
SupplierPlants = Db.SupplierPlants.Local;
Now I have RowEnter event bound for the Supplier DataGridView so that it will only show Plants for the selected Suppliers:
private void dgvSuppliers_RowEnter(object sender, DataGridViewCellEventArgs e)
{
var supplier = ((Supplier)dgvSuppliers.Rows[e.RowIndex].DataBoundItem);
if (supplier == null)
return;
ShowSupplierPlants(supplier.SupplierID);
}
private void ShowSupplierPlants(int supplierID)
{
var plantData = AppData.SupplierPlants.Where(x => x.SupplierID == supplierID); //Get selected Suppliers Plant Data.
if (plantData.Any())
bsSuppliersPlants.DataSource = plantData;
else
bsSuppliersPlants.DataSource = new List<SupplierPlant>();
dgvSupplierPlants.Refresh();
}
The issue is when I call AppData.Db.SaveChanges(); it will correctly apply all changes to the Suppliers Table but it wont Add new rows for the SupplierPlants table as I have taken a subset of the local db.
Do I have to manually manage new rows added for this Table as I am using a subset and not the whole Local db?
You should insert them manually,
Db.SupplierPlants.Add(item);
Detailed information
Hope helps,
just as a FYI i bound the DGV CellEndEdit and just added the newly added line to the context like so:
private void dgvSupplierPlants_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
var data = ((SupplierPlant)((DataGridView)sender).Rows[e.RowIndex].DataBoundItem); //Get the Data for the edited Row.
if (AppData.Db.Entry(data).State == EntityState.Detached)
{
AppData.SupplierPlants.Add(data);
}
}

C# Visual Studio: How do I update a DB from Edit with DataGridView using LINQ?

I have a form WinForms form window with a DataGridView. It pulls data from a SQL Server Express database using Linq and displays it in the DataGridView columns properly. I have it set in the properties to allow editing. When I edit and change a field during runtime it will only update the database if I specify one column name. This doesn't work well because I need it to update the column I edit, not the one hard coded. It needs to be dynamic. See the comments next to site.??? I can choose a column name manually from site.whatever but that's not what I want. I want to be able to do Site.columnname from the string I set.
I see other examples loading and/or editing a DataGridView with data, but these examples are not using LINQ.
My form load code:
public partial class EditImage : Form
{
SQL sqlLink = new SQL();
CustomMessageBox msg = new CustomMessageBox();
public EditImage()
{
InitializeComponent();
}
private void EditImage_Load(object sender, EventArgs e)
{
dgImageView.DataSource = sqlLink.getImageList();
dgImageView.AutoResizeColumns();
dgImageView.AutoResizeRows();
}
private void dgImageView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
int rid = e.RowIndex;
int dbrid = rid + 1;
int cid = e.ColumnIndex;
string change = dgImageView[cid, rid].Value.ToString();
string columname = dgImageView[cid, rid].OwningColumn.Name;
using (var dc = new DbLink())
{
var site = (from img in dc.images where img.id == dbrid select img).SingleOrDefault();
if (site != null)
{
try
{
site.??? = change;
dc.SubmitChanges();
dgImageView.EndEdit();
}
catch (Exception ex)
{
msg.Text("Error", ex.ToString(), MessageBoxButtons.OK);
}
}
}
}
Code from SQL class to retrieve DataSource:
public IQueryable getImageList()
{
return selectImageList();
}
and
private IQueryable selectImageList()
{
DbLink dbl = new DbLink();
image tl = new image();
var results = from imgs in dbl.images
select imgs;
return results;
}
A screenshot of the dbml file:
You could try with reflection:
var changedColumn = typeof(image).GetProperty(columnName);
changedColumn.SetValue(site,change);

Skip to a database record in c#

Here is some background on what I have been following.
http://www.homeandlearn.co.uk/csharp/csharp_s12p9.html
That will go to the last or first record of the database. I want to skip to a record in the access database that the user wants by inputting the ID number in a textbox and then the correct row will get put in the textboxes.
I think I can use this code from the above website. I have implemented everything else from the website above.
Global variable
int inc = 0;
The navigate records that I will call in my Skip button later
private void NavigateRecords()
{
DataRow dRow = ds1.Tables["Laptops"].Rows[inc];
txtMaker.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(1).ToString();
txtModel.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(2).ToString();
txtPrice.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(3).ToString();
txtBids.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(4).ToString();
txtScreen.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(5).ToString();
txtCPU.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(6).ToString();
txtMemory.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(7).ToString();
txtHD.Text = ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(8).ToString();
picLaptops.Image = Image.FromFile(ds1.Tables["Laptops"].Rows[inc].ItemArray.GetValue(9).ToString());
}
My skip button so far...
private void btnSkip_Click(object sender, EventArgs e)
{
NavigateRecords();
}
It is hard for me to do this. I know what I want but lack the technical skill to do it. It is very frustrating. I have no idea what to do.
If someone can work it out and show me the code I can then understand it and use it elsewhere.
Here is an example of the next button to go to the next record if that helps.
private void btnNext_Click(object sender, EventArgs e)
{
if (inc != MaxRows - 1)
{
inc++;
NavigateRecords();
}
else
{
MessageBox.Show("You have reached the end of available items", "End of Available Items", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
Use data binding, instead of assigning values manually to controls.
create a model class
public class MyClass
{
public string Maker { get; set; }
public double price { get; set; }
// and so on, for all your fields
}
Add a object data source for MyClass in the "Data Sources" explorer in Visual Studio.
Drag the fields form the Data Sources to your form. Visual Studio automatically add a BindingSource and a BindingNavigator to your form.
Assign your data to the BindingSource in the form:
this.bindingSource1.DataSource = myData;
Where myData is some enumeration of MyClass objects.
You can do this for database sources as well. But personally I prefer to have my data in classes. Is's easier to handle, than either manipulating DataSets or form fields directly.
Based on your description, I think this is what you want
void btnNext_Click(object sender, EventArgs e) {
int id = Int32.Parse(yourIdTextBox.Text);
DataRow row = ds1.Tables["Laptops"].Rows.OfType<DataRow>()
.SingleOrDefault(r => (int)r.ItemArray[your id index] == id);
if (row == null)
{
//user typed in invalid row id
} else
processRow(row);
}
void processRow(DataRow row){
txtMaker.Text = row.ItemArray.GetValue(1).ToString();
txtModel.Text = row.ItemArray.GetValue(2).ToString();
txtPrice.Text = row.ItemArray.GetValue(3).ToString();
txtBids.Text = row.ItemArray.GetValue(4).ToString();
txtScreen.Text = row.ItemArray.GetValue(5).ToString();
txtCPU.Text = row.ItemArray.GetValue(6).ToString();
txtMemory.Text = row.ItemArray.GetValue(7).ToString();
txtHD.Text = row.ItemArray.GetValue(8).ToString();
picLaptops.Image = Image.FromFile(row.ItemArray.GetValue(9).ToString());
}
Which would then simplify your NavigateRecors() method to
private void NavigateRecords()
{
DataRow dRow = ds1.Tables["Laptops"].Rows[inc];
processRow(dRow);
}

Categories

Resources