简体   繁体   中英

C# Entity Framework ObjectContext instance has been disposed

I get the following error when I want to iterate over a List

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

I open the Form with the following code

        private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            int id = int.Parse(dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString());
            Aufenthalt a;
            using (var db = new GastContext())
            {
                a = db.Aufenthalte.First(x => x.AufenthaltID == id);
            }

            Aufenthaltsform frm = new Aufenthaltsform(currentGast, a);
            frm.ShowDialog();
        }

And this is the constructor of my form and here my Application throws the above error

    public Aufenthaltsform(Gast g, Aufenthalt a)
    {
        InitializeComponent();

        MessageBox.Show(a.Mitreisende.Count.ToString());
    }

That's the Aufenthalt-Object

    public class Aufenthalt
    {
        public int AufenthaltID { get; set; }
        public DateTime Anreisedatum { get; set; }
        public DateTime Abreisedatum { get; set; }

        public virtual List<Mitreisender> Mitreisende { get; set; }

        public virtual Gast Gast { get; set; }

        public Aufenthalt()
        {
            Mitreisende = new List<Mitreisender>();
        }
    }

Your Aufenthalt has two navigation properties - Mitreisende and Gast . Which require non-disposed DbContext when you are using lazy-loading. That's why you have error when try read those properties after disposing context via using statement:

Aufenthalt a;
using (var db = new GastContext())
{
    a = db.Aufenthalte.First(x => x.AufenthaltID == id);
}

// db is disposed here
Aufenthaltsform frm = new Aufenthaltsform(currentGast, a);

You can:

  • remove using statement to keep context alive
  • use eager loading instead of lazy loading
  • move form creation and displaing inside using statement
  • get Mitreisende count and pass number into form instead of passing root object and using navigation property later

First option - DbContext is a lightweight object, it's ok not to dispose it.

var db = new GastContext();
Aufenthalt a = db.Aufenthalte.First(x => x.AufenthaltID == id);
Aufenthaltsform frm = new Aufenthaltsform(currentGast, a);

Second option - not very good option, because you only need count of related entities. Why loading them all into memory? But you can

Aufenthalt a;
using (var db = new GastContext())
{
    a = db.Aufenthalte.Include(x => x.Mitreisende).First(x => x.AufenthaltID == id);
}

Aufenthaltsform frm = new Aufenthaltsform(currentGast, a);   

Third option is obvious

using (var db = new GastContext())
{
    Aufenthalt a = db.Aufenthalte.First(x => x.AufenthaltID == id);
    Aufenthaltsform frm = new Aufenthaltsform(currentGast, a);
    frm.ShowDialog();
}

And best option is not passing to form data which are not required. It needs only count of Mitreisende, not whole collection. So change your form to

public Aufenthaltsform(Gast g, int mitreisendeCount)
{
    InitializeComponent();
    MessageBox.Show(mitreisendeCount.ToString());
}

And call it this way

int mitreisendeCount;
using (var db = new GastContext())
{
    mitreisendeCount = db.Aufenthalte.First(x => x.AufenthaltID == id).Mitreisende.Count;
}

Aufenthaltsform frm = new Aufenthaltsform(currentGast, mitreisendeCount );

You should ensure that the query is executed before the context is disposed:

a = db.Aufenthalte.First(x => x.AufenthaltID == id);
// place this within the disposable context (using)
int count = a.Mitreisende.Count;

The object a itself is filled after loading, but it has a navigation property Mitreisende that has not been filled yet at that moment (and Entity Framework also remembers that it has not done so yet).

The moment you call a.Mitreisende.Count , Entity Framework tries to fill the Mitreisende property, but it can not do so because the using statement caused the DbContext to be disposed, leading to the error.

There are multiple fixes:

1) Don't dispose the DbContext, simply by removing the using block. .NET will remove it by itself a little later, which in many cases will not hurt.

2) Dispose the DbContext by yourself, but do it a little later by putting the next 2 lines inside the block, instead of after it.

3) Make sure that Entity Framework loads the Mitreisende as soon as possible instead of delaying it, using an .Include statement:

a = db.Aufenthalte.Include(x => x.Mitreisende).First(x => x.AufenthaltID == id);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM