Edward Elhoc
Edward Elhoc

Reputation: 43

Error "An entity object cannot be referenced by multiple instances of IEntityChangeTracker"

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.

enter image description here

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

Answers (1)

CodingYoshi
CodingYoshi

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

Related Questions