Entity framework object context saves new entities that were not added - c#

I have been working with Entity Framework (VS2010 Framework 4.0) in my proyect. I had some trouble with using a different object context per form. What I did then, was to create a object context in the Main Menu Form (stays opened) and everytime I create and show one form, I pass that object context to this new form. Example:
public partial class frm_Menu : Base
{
public Sistema_financiero_Entities db = new Sistema_financiero_Entities();
private void cancelarCuotaToolStripMenuItem_Click(object sender, EventArgs e)
{
frm_Cancelacion_Cuota Form1 = new frm_Cancelacion_Cuota();
Form1.db = db;
Form1.Show();
}
}
Ok, that solution worked fine until now because I needed to use and pass objects throw the differents forms sometimes, and if the objects contexts were different, I got an error.
Now, I have detected a huge issue using it this way. I have a form, where I can pay for the different installments of a loan. I´ll attach an image so then you can see what I´m talking about.
There, you select the different installments you want to pay for. Then, you introduce the value you will finally pay in "Total cobrado". Here is the important thing: When the checkbox image is checked (the blue one - already checked in the image), I create a "payment" entity per installment. Every "payment" object is stored in a list. If I uncheck it, I can change the value and the same thing is done. Obviously, I´m clearing the list before doing a list.Clear();. Then, one the checkbox checked, I can press "Aceptar" (accept). There I add to the database every "payment"(PAGO) in the list. After that, I save all changes.
foreach (Pago p in Lista_nuevos_pagos)
{
db.AddToPago(p);
}
try
{
db.SaveChanges();
this.Close();
}
My problem, is that it´s not only adding those "payments" in the list but the other "payments" entities that were in the list before clearing it. I reach the conclusion that when I clear the list, the objects remains in the object context. I thought that if the entity is not in the database, I have to Add it to the entity in the object context as I did with pago (db.AddToPago(p);).
I wanted to ask you guys how can I solve this issues. I solved it now doing this:
private void cancelarCuotaToolStripMenuItem_Click(object sender, EventArgs e)
{
Sistema_financiero_Entities db = new Sistema_financiero_Entities();
frm_Cancelacion_Cuota Form1 = new frm_Cancelacion_Cuota();
Form1.db = db;
Form1.Show();
}
Instead of creating just one global db for all forms, I create one in the Main Menu for every form. Then, in that form closed event, I dispose that object context.
Then, when i check the checkbox image, before creating the "payments", I delete every "Pago" entity from the object context:
foreach (Pago p in Lista_nuevos_pagos)
{
db.DeleteObject(p);
}
Lista_nuevos_pagos.Clear();
Doing this works correctly, but I´m still having trouble with some other created entities (Installments) that are not deleted when I clear a list. I think I´m doing it wrongly, thats why I need some direction to use EF correctly. I really need to get this done really soon, I don´t have too much time to read EF tutorials.
Just in case, this is how I create every "Pago" (payment)
Pago p = new Pago();
p.desc_aumento_intereses = nudwb1.Value;
p.desc_aumento_punitorios = nudwb2.Value;
p.desc_aumento_gastos = nudwb3.Value;
p.desc_aumento_comision = nudwb4.Value;
p.cotizacion = ntxt_Cotizacion.Value;
p.fecha_hora = fecha_hora;
Cuota c = new Cuota();
string name = tbx.Name.Substring(tbx.Name.IndexOf("-") + 1);
int nro_cuota = Convert.ToInt32(name);
c = Lista_cuotas_cobrar.Where(x => x.num_cuota == nro_cuota).First();
p.Cuota.Add(c);
Thank you for reading, I know this is a lot of info. Hope some guide soon..

I guess that you have references to those object in your Lista_nuevos_pagos list. This is why they will be duplicated.

Related

C# selectionchanged item implementing database error in Visual Studio with Entity Framework

I'm trying to change my application to implement a database. I've managed to change most but this code is not working for me:
private void FleetList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (btnRmvFleet != true)
/*{
Cars = ((Fleet)FleetList.SelectedItem).Car;
CarList.ItemsSource = Cars; // what the code was before I changed it
boxFirstCar.DataContext = Cars;
}*/
{
db.Cars = ((Fleet)FleetList.SelectedItem).Car;
CarList.ItemsSource = db.Cars; // how I'm trying to make it work
boxFirstCar.DataContext = db.Cars;
db.SaveChanges();
}
else
{
btnRmvFleet = false;
}
}
I get an error at
((Fleet)FleetList.SelectedItem).Car;
I tried to add database to some things but I must be missing something..
Thanks for your help in advance!
Screenshot of the error:
LINK
Ask for whatever more you need. Just know I'm not very experienced in stackoverflow or C#
About my code:
in every fleet there are different cars. Therefore I want my app to change the cars list to the cars of the fleet selected. So when you select another fleet, you will get to see the cars from that fleet.
The cars and the fleets are in a (code-first) database.
I use Entity Framework and I am trying to change the list of cars showing in my application. When you select another fleet, it should show different cars.
Just to clarify, the code between /* */ works! But now i am trying to implement the database.

DataGridView is editable but does not send changes back to database using Entity Framework

I've bound my DataGridView to my ComboBox so that whatever value is selected in the ComboBox, the corresponding valued for SID and Mark will appear in the DataGridView. The DataGridView is editable when I do this but the data is not saved in the database when it is input. Is there a way to update it? If there's another method, I have to first warn that I only need SID and Mark in the DataGridView, if I try to bind the whole "Student_Course" table to the DataGridView I get other columns I don't need.
private void cboeCID_SelectedIndexChanged_1(object sender, EventArgs e)
{
var CID = Convert.ToInt32(cboeCID.Text);
using (var db = new Entities2())
{
var course = from c in db.Student_Course
where c.CID == CID
select new Class1
{
SID = c.SID,
Mark = c.Mark
};
editDataGridView.DataSource = course.ToList();
Validate();
editDataGridView.EndEdit();
editDataGridView.Update();
}
}
class Class1
{
public int SID { get; set; }
public int Mark { get; set; }
}
There are some important issues in above code:
You shaped the result of query to a custom Class1 which is not your entity type.
You used a DbContext in using statement which means db is disposed after the using statement and will not track changes.
You called SaveChanges on another instance of your DbContext which is not aware of changes, so nothing happens.
To solve above issues consider these tips:
Create db as a field of Form and instantiate it in Load event of Form and use it for both loading and saving data.
You can load data entity this way:
db = new Entities2();
db.Student_Course.Where(x => c.CID== CID).ToList();
editDataGridView.DataSource = db.Student_Course.Local;
You can save data this way:
editDataGridView.EndEdit();
db.SaveChanges();
If you need to use a view model different than your entity for edit, when saving changes you should first load original entities from database using another instance of your context, then for each entity set the value of changed field and then call SaveChanges method.
For more information take a look at these resources:
Entity Framework Databinding with WinForms
Entity Framework Add/Attach Entity States

C# Pointers and Properties

I'm making a windows forms application and I'm trying to improve my code so I'd like a little bit of advice/help.
I have a list with data at lets say my first form that I add data to from a database. I then pass around one persons details from that list rather than the whole list. My Problem is that I don't think I'm passing around data correctly and I'd like to do it correctly.
Example of what I'm doing (accountholders is of type object?):
Form 2 =I want to pass the data into this form:
private AccountHolders person;
public void SetThePersonsValue(AccountHolders inputAccountHolder)
{
person = inputAccountHolder;
}
Form 1 = I'm taking data from this form, I want to update the list that in this form later on:
WithdrawNoReceipt withdrawNoReceipt = new WithdrawNoReceipt();
withdrawNoReceipt.SetThePersonsValue(person);
withdrawNoReceipt.ShowDialog();
So I want to use a get/set property (?) to do this but I'm not sure how to do so.. Ideally I want the person I'm passing around to be a pointer so the originally list gets updated so I can write the data back to the database without passing the data back to the first form.
If you need any more information please let me know! Thanks in advance.
Are you referring to a property? because then you need to add the following code
private AccountHolders person;
public AccountHolders Person
{
get{return person;}
set{person = value;}
}
the property points to the private member person. Ideally you add a PropertyChanged event in the property so your form knows something has been updated?
EDIT:
For filling the property value, value is of type AccountHolders
public void SetThePersonsValue(AccountHolders inputAccountHolder)
{
//Set the value
Person = inputAccountHolder;
}
WithdrawNoReceipt withdrawNoReceipt = new WithdrawNoReceipt();
//get the value
WithdrawNoReceipt.SetThePersonsValue(Person);
WithdrawNoReceipt.ShowDialog();
while debugging you will now see you person object changes whenever you update your Person object

Browsable(false) at run time?

I am using a datasource to populate my datagridview with the data. However, im trying to find a way for the user to be able to hide columns that he does not want to see.
I am able to hide and show columns before the program runs using:
[Browsable(false)]
public string URL
{
get
{
return this._URL;
}
set
{
this._URL = value;
this.RaisePropertyChnaged("URL");
}
}
I cannot seem to figure out how to change the [Browsable(false)] at run time.
Any ideas how I could accomplish this?
Basically, I want to bind an "on/off" to a menu.
Apologies if im not using the right terminology when explaining my problem, I am self taught and started a few weeks ago - so still very newbie :)
Edit:
Cant hide the column because when i run my update function all columns appear again. Here is my function for updating:
private void UpdateResults()
{
Invoke(new MethodInvoker(
delegate
{
this.dgvResults.SuspendLayout();
this.dgvResults.DataSource = null;
this.dgvResults.DataSource = this._mySource;
this.dgvResults.ResumeLayout();
this.dgvResults.Refresh();
}
));
}
At run time, you can just specify the column as being invisible:
dgv.Columns["ColumnName"].Visible = false;
The way to do this properly at runtime is to provide a custom ITypedList implementation on the collection, or provide a TypeDescriptionProvider for the type, or (for single-object bindings, not lists), to implement ICustomTypeDescriptor. Additionally, you would need to provide your own filtered PropertyDescriptor implementation. Is it really worth it? In most cases: no. It is much easier to configure the grid properly, showing (or not) the appropriate columns by simply choosing which to add.
Indeed, as others had mention the purpose of BrowsableAttribute is different, but I understand what you want to do:
Let's suppose that we want to create a UserControl than wraps a DataGridView and gives the user the ability to select which columns to display, allowing for complete runtime binding. A simple design would be like this (I'm using a ToolStrip, but you can always use a MenuStrip if that's what you want):
private void BindingSource_ListChanged(object sender, ListChangedEventArgs e) {
this.countLabel.Text = string.Format("Count={0}", this.bindingSource.Count);
this.columnsToolStripButton.DropDownItems.Clear();
this.columnsToolStripButton.DropDownItems.AddRange(
(from c in this.dataGrid.Columns.Cast<DataGridViewColumn>()
select new Func<ToolStripMenuItem, ToolStripMenuItem>(
i => {
i.CheckedChanged += (o1, e2) => this.dataGrid.Columns[i.Text].Visible = i.Checked;
return i;
})(
new ToolStripMenuItem {
Checked = true,
CheckOnClick = true,
Text = c.HeaderText
})).ToArray());
}
In this case, bindingSource is the intermediary DataSource of the dataGrid instance, and I'm responding to changes in bindingSource.ListChanged.

Two comboBoxes with same members, when one selected, other must be unable to select same member

So I have two comboBoxes (comboBoxFromAccount and comboBoxToAccount). Each has the same datasource, which is AccountsList (a list of BankAccount objects that was passed from the parent form).
I would like to make it so that if an item is selected in one of the comboBoxes, it would no longer be selectable in the other. The way I'm trying to do this is by copying the list of BankAccounts from the comboBoxFromAccount to the comboBoxTo account, and removing the selected index of comboBoxFromAccount from the comboBoxToAccount.
I think I'm close, but what seems to happen is I have a blank comboBoxToAccount.
Here is my code:
private BankAccountCollection accountsListTransferTo = new BankAccountCollection();
// public property for passing collection data to the dialog
public BankAccountCollection AccountsList
{
get { return accountsListTransferTo; }
set { accountsListTransferTo = value; }
}
// Initial loading
private void TransferFundsDialog_Load(object sender, EventArgs e)
{
textBoxAmount.Text = String.Empty;
textBoxAmount.Select();
comboBoxFromAccount.DataSource = AccountsList;
accountsListTransferTo.AddRange(AccountsList); // Copy content
accountsListTransferTo.Remove(comboBoxFromAccount.SelectedItem as BankAccount); // Remove item
comboBoxToAccount.DataSource = accountsListTransferTo; // Data binding
}
private void comboBoxFromAccount_SelectedIndexChanged(object sender, EventArgs e)
{
accountsListTransferTo.Clear(); // Clear list, if you don't to it, AddRange will just add more items.
accountsListTransferTo.AddRange(AccountsList); // Copy ALL accounts
accountsListTransferTo.Remove(comboBoxFromAccount.SelectedItem as BankAccount); // Remove selected, so user cannot transfer to same account
// Refresh data binding
comboBoxToAccount.DataSource = null;
comboBoxToAccount.DataSource = accountsListTransferTo;
// Select very first item in "TO" combobox
comboBoxToAccount.SelectedIndex = 0;
}
Help would be appreciated.
Try removing the line
comboBoxToAccount.DataSource = null;
I have a vague recollection about comboboxes having problems with this.
Another possible problem that I can see is that you are using accountsListTransferTo both as your master collection and the one where you are removing the selected account from. Every time comboBoxFromAccount_SelectedIndexChanged is called one more account will disappear from the collection (and therefore from the available options in comboBoxToAccount).
I think I have seen comboboxes behave in a way where the SelectedIndexChanged (or a similar) event is triggered as new items are being added. If that is the case here it will explain the empty comboBoxToAccount, because comboBoxFromAccount_SelectedIndexChanged will run once for each bank account being added, essentially removing them from the master list and then rebinding the reduced list. You can easily verify this with a break point in your event handler.

Categories

Resources