如何修复“ObjectContext 实例已被处置”

Posted

技术标签:

【中文标题】如何修复“ObjectContext 实例已被处置”【英文标题】:How can I fix "The ObjectContext instance has been disposed " 【发布时间】:2020-06-10 01:12:53 【问题描述】:

我开发了一个带有实体框架的应用程序。我明白了

ObjectContext 实例已被释放,不能再使用 用于需要连接的操作。

有时会出错。

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

家庭控制器:

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

    


【问题讨论】:

如何初始化noteManager?而noteManagerDBContext是什么关系? 【参考方案1】:

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

如果noteManager.ListQueryable() 返回IQueryable&lt;Note&gt;,快速解决方法是:

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 次,每返回一个音符行一次。这是 EF 和 DB 在实体的代理持有对 DbContext 的弱引用时需要协商的大量查询。如果请求在序列化程序完成实体之前处理 DbContext,则您将收到一个正在处理的异常。

但是,即使使用即时加载,如果任何相关实体本身都有子实体,这也可能是一个兔子洞。加载视图可能不需要的所有相关数据也会对性能/资源产生影响。

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

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

【讨论】:

以上是关于如何修复“ObjectContext 实例已被处置”的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 npm 审计修复问题?

如何修复drv?

如何修复漏洞

如何修复WMI

PHP网站漏洞怎么修复 如何修补网站程序代码漏洞

如何修复这些漏洞? (npm audit fix 无法修复这些漏洞)