【问题标题】:C# Entity Framework ObjectContext instance has been disposedC# Entity Framework ObjectContext 实例已被释放
【发布时间】:2017-02-01 15:41:14
【问题描述】:

当我想遍历列表时出现以下错误

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

我用以下代码打开表单

        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();
        }

这是我的表单的构造函数,在这里我的应用程序抛出上述错误

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

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

那是 Aufenthalt 对象

    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>();
        }
    }

【问题讨论】:

标签: c# entity-framework


【解决方案1】:

您的 Aufenthalt 有两个导航属性 - MitreisendeGast。当您使用延迟加载时,这需要非处置的DbContext。这就是为什么在通过using 语句处理上下文后尝试读取这些属性时出现错误的原因:

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);

你可以:

  • 删除 using 语句以保持上下文活动
  • 使用预先加载而不是延迟加载
  • using 语句中移动表单创建和显示
  • 获取 Mitreisende 计数并将数字传递到表单中,而不是传递根对象并稍后使用导航属性

第一个选项 - DbContext 是一个轻量级的对象,不处置也没关系。

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

第二个选项 - 不是很好的选项,因为您只需要相关实体的数量。为什么要将它们全部加载到内存中?但是你可以

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);   

第三个选项很明显

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

最好的选择是不传递给不需要的表单数据。它只需要计数 Mitreisende,而不需要整个集合。因此,将您的表单更改为

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

这样称呼它

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

Aufenthaltsform frm = new Aufenthaltsform(currentGast, mitreisendeCount );

【讨论】:

  • 或者使用.Include
【解决方案2】:

您应该确保在释放上下文之前执行查询:

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

【讨论】:

    【解决方案3】:

    对象a本身在加载后被填充,但它有一个导航属性Mitreisende,此时尚未填充(实体框架也记得它还没有填充)。

    在您调用a.Mitreisende.Count 的那一刻,Entity Framework 尝试填充 Mitreisende 属性,但它无法这样做,因为using 语句导致 DbContext 被释放,从而导致错误。

    有多个修复:

    1) 不要丢弃 DbContext,只需删除 using 块。 .NET 稍后会自行删除它,这在许多情况下不会受到伤害。

    2) 自己处理 DbContext,但稍后将接下来的 2 行放在块内,而不是放在块之后。

    3) 使用.Include 语句确保实体框架尽快加载Mitreisende 而不是延迟它:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多