Reputation: 43
friends. I really need your help. I would be very grateful.
And so I have the entity "Model" c field "ID_model" and "name" in MS SQL Server. I want, after clicking "Edit" on Form1, there is another form (FormModel) where you can change the data and write changes to the database.
The problem is that after pressing "Edit" there is an error about "Additional information: An entity object cannot be referenced by multiple instances of IEntityChangeTracker" And I don't know how to fix it.
Code from Form1:
public partial class Form1 : Form
{
MyDBEntities db2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
db2 = new MyDBEntities();
modelBindingSource.DataSource = db2.Models.ToList();
dataGridView.Columns.RemoveAt(2);
}
private void btnEdit_Click(object sender, EventArgs e)
{
if (modelBindingSource.Current == null)
return;
using (FormModel frm = new FormModel(modelBindingSource.Current as Model))
{
if (frm.ShowDialog() == DialogResult.OK)
{
modelBindingSource.DataSource = db2.Models.ToList();
}
}
}
}
Code from FormModel:
public partial class FormModel : Form
{
MyDBEntities db2;
public FormModel(Model obj)
{
InitializeComponent();
db2 = new MyDBEntities();
if (obj == null)
{
modelBindingSource.DataSource = new Model();
db2.Models.Add(modelBindingSource.Current as Model);
}
else
{
modelBindingSource.DataSource = obj;
db2.Models.Attach(modelBindingSource.Current as Model);
}
}
private void FormModel_FormClosing(object sender, FormClosingEventArgs e)
{
if (DialogResult == DialogResult.OK)
{
if (string.IsNullOrEmpty(txtModelName.Text))
{
MessageBox.Show("There are empty fields", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Information);
txtModelName.Focus();
e.Cancel = true;
return;
}
db2.SaveChanges();
e.Cancel = false;
}
e.Cancel = false;
}
}
I really hope help. All the best. And excuse me for my English.
Upvotes: 4
Views: 271
Reputation: 27039
In Form1
you have this code (note I have replaced some code with comments for brevity):
public partial class Form1 : Form
{
// code...
private void Form1_Load(object sender, EventArgs e)
{
// code...
modelBindingSource.DataSource = db2.Models.ToList();
// code...
}
private void btnEdit_Click(object sender, EventArgs e)
{
// code...
using (FormModel frm = new FormModel(modelBindingSource.Current as Model))
{
// code...
}
}
}
The code modelBindingSource.DataSource = db2.Models.ToList();
is setting the DataSource
property to Models
. Everything in Models
is loaded from the database; in other words, the db2
context has everything in Models
. You just got it from db2
so it must be there.
The code using (FormModel frm = new FormModel(modelBindingSource.Current as Model))
is sending the Model
to the FormModel
constructor.
Then in FormModel
, you have this code:
public partial class FormModel : Form
{
MyDBEntities db2;
public FormModel(Model obj)
{
db2 = new MyDBEntities();
// code...
db2.Models.Attach(modelBindingSource.Current as Model);
}
// code...
}
See in the above code you are attaching the Model
to a new context named db2
but since Model
is already attached to db2
in Form1
, the exception is thrown and it is clearly telling you this:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
The message could not be any clearer than that.
Fix
Remove this line of code db2.Models.Attach(modelBindingSource.Current as Model);
so you are not attaching it. Not sure why you are doing that. See this answer for why and when you need to call Attach
.
Clean Up
Actually from the code you have posted, the obj
in FormModel
constructor can never be null so this is all the code you need in FormModel
:
public partial class FormModel : Form
{
public FormModel(Model obj)
{
InitializeComponent();
modelBindingSource.DataSource = obj;
}
private void FormModel_FormClosing(object sender, FormClosingEventArgs e)
{
if (DialogResult == DialogResult.OK)
{
if (string.IsNullOrEmpty(txtModelName.Text))
{
MessageBox.Show("Есть пустые поля", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Information);
txtModelName.Focus();
e.Cancel = true;
return;
}
}
}
}
Then you call SaveChanges
in your Form1
like this:
using (FormModel frm = new FormModel(modelBindingSource.Current as Model))
{
if (frm.ShowDialog() == DialogResult.OK)
{
modelBindingSource.DataSource = db2.Models.ToList(); // not sure if you need this
db2.SaveChanges(); // <-- call save here since the dialog has been closed.
}
}
Additional Notes
Just a final note, FormModel
and Form1
are not good names for forms. Good names for forms should show the intention of the form. For example, names like OrderEntryForm
, OrderDetailForm
etc. are good names.
Upvotes: 1