我该如何修复 "The ObjectContext instance has been disposed "

How can I fix "The ObjectContext instance has been disposed "

我用 entity framework 开发了一个应用程序。我得到

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

有时会出错。

我在互联网上做了一些研究,但我无法弄明白。如果您能提供帮助,我将不胜感激

家庭控制器:

public ActionResult Index()
{
    return View(noteManager.ListQueryable().Where(x => x.IsDraft == false && x.IsApproved == true).OrderByDescending(x => x.ModifiedOn).Take(10).ToList());
}

我的笔记实体:

public class Note : MyEntitesBase
{       
    public string Tittle { get; set; }
    public string Text { get; set; }
    public bool IsDraft { get; set; }
    public int LikeCount { get; set; }
    public int CategoryID { get; set; }

    public virtual EvernoteUser Owner { get; set; } 
    public virtual List<Comment> Comments { get; set; } 
    public virtual Category Category { get; set; } 
    public virtual List<Liked> Likes { get; set; } 

    public Note()
    {
        Comments = new List<Comment>();
        Likes = new List<Liked>();
    }

}

我的评论实体:

public class Comment : MyEntitesBase
{
    public string Text { get; set; }
    public bool CommentStatus { get; set; }

    public virtual Note Note { get; set; }
    public virtual EvernoteUser Owner { get; set; } 
}

我的数据库上下文:

public class DatabaseContext :DbContext 
{
   public DbSet<EvernoteUser> EvernoteUsers { get; set; }
   public DbSet<Note> Notes { get; set; }
   public DbSet<Comment> Comments { get; set; }
   public DbSet<Category> Categories { get; set; }
   public DbSet<Liked> Likes { get; set; }

   public DatabaseContext()
   {           
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<DatabaseContext,Configuration>()); 

    }

}

此问题通常源于序列化程序,序列化程序会触及正在序列化的实体的所有属性以发送到视图。如果与实体关联的 DbContext 被释放,序列化程序将在尝试发出查询以加载相关详细信息时命中此事件。

快速修复,如果 noteManager.ListQueryable() returns IQueryable<Note> 将是:

return View(noteManager.ListQueryable()
    .Include(x => x.Owner)
    .Include(x => x.Comments)
    .Include(x => x.Category)
    .Include(x => x.Likes)
    .Where(x => x.IsDraft == false && x.IsApproved == true)
    .OrderByDescending(x => x.ModifiedOn)
    .Take(10).ToList());

这会立即加载相关实体和注释。预加载和延迟加载之间的区别在于,对于预加载,EF 将生成 SQL 以连接所有关联的表,然后检索最多 10 个选定行的相关行。使用延迟加载,您可能有 10 个注释行,例如 ID 的 1-10,但是当每个 属性 被触摸时,EF 将生成如下查询:

SELECT * FROM Owners WHERE OwnerID = 22 -- 笔记 1 上的所有者 ID

SELECT * FROM Comments WHERE NoteId = 1

SELECT * FROM Categories WHERE CategoryId = 4 注释 1 上的类别 ID

SELECT * FROM Likes WHERE NoteId = 1

然后再重复 9 次,每返回一个注释行一次。当实体的代理持有对 DbContext 的弱引用时,EF 和 DB 需要协商很多查询。如果请求在序列化程序完成实体之前处理 DbContext,您将收到一个异常异常。

但是,即使使用预加载,如果这些相关实体中的任何一个本身具有子实体,这也可能是一个兔子洞。还有 performance/resource 加载您的视图可能不需要的所有相关数据的影响。

更好的长期解决方案是定义可序列化的 ViewModel 来表示您的视图实际需要显示的数据结构,然后利用 Select 或 Automapper 的 ProjectTo 用来自实体结构。这消除了急切加载数据的需要,只需从结构中 Select,EF 将计算出 SQL。它还消除了序列化程序中延迟加载命中的风险,前提是您来自实体而不是实体本身的 Select 字段。这也可以大大减少服务器和客户端在请求时存储数据所需的内存量,以及数据传输大小。

将视图模型传递给视图意味着将相同或不同的视图模型传递回服务器,而不是尝试将实体传递回、附加和保存...与再次加载数据并复制值。但是,这要安全得多,因为您不会冒着陈旧、不完整或可能被篡改的数据覆盖您的真实数据的风险。无论如何,您应该在执行更新时始终重新加载实体,以验证并检查行自发送到客户端后是否未被修改。不要相信来自 Web 客户端的任何信息。将字段复制到新加载的实体也意味着更高效的 UPDATE 语句作为附加 + EntityState.Modified 或使用 DbContext.Update() 导致更新语句更新 所有 字段, 与跨复制相比,只有更改的值才会添加到 UPDATE 语句中。