无法访问已释放的上下文实例 EF 核心

Posted

技术标签:

【中文标题】无法访问已释放的上下文实例 EF 核心【英文标题】:Cannot access a disposed context instance EF core 【发布时间】:2021-06-24 02:01:51 【问题描述】:

我正在开发一个 .net core mvc 和 EF 的 CRM,它需要大量的数据库连接来检索和更新信息。调试时时不时会遇到这个错误,这个项目很大,用户很多,不知道实际使用效果如何!

无法访问已释放的上下文实例。此错误的一个常见原因是释放从依赖注入中解析的上下文实例,然后尝试在应用程序的其他地方使用相同的上下文实例。如果您在上下文实例上调用“Dispose”或将其包装在 using 语句中,则可能会发生这种情况。如果你使用依赖注入,你应该让依赖注入容器处理上下文实例。\r\n对象名称:'XXX'。

在我在 startup.cs 中使用此设置之前:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .ServiceLifetime.Singleton);

该设置偶尔会导致另一个错误:

System.InvalidOperationException:无法跟踪实体类型“TblZZZ”的实例,因为已经在跟踪具有相同键值 'ZZZId' 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

所以我将设置更改为:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

现在我面对的是Cannot access a disposed context instance。我不知道什么设置可以解决我的问题。

我正在使用 net5.0

更新: 我的部分课程:

public partial class TblXXX
    
        private ZZZ context;//context
        public TblXXX(ZZZ _context)
        
            context = _context;
        
        public TblXXX()  
//function for check username
   public bool CheckUsernameExit(string username) 
            var u = context.TblXXX
                .Where(e => e.Username == username)
                .FirstOrDefault();
            return (u != null);
        

在我的控制器中:

  public IActionResult Check(UserModelView user)
        
            if (ModelState.IsValid)
            
                var r = _viewModel.tblXXX.CheckUsernameExit(user.tblXXX.Username);
                if (r)
                
                    toastNotification.AddErrorToastMessage("This email is in use. Enter differernt email.");
                 
                    return View("Create", _viewModel);
                
            

这是我的 ViewModel:

 public class UserModelView
    
        public TblXXX tblXXX  get; set; 
        public List<TblXXX > tblXXXList  get; set; 
    
          

这是我遇到错误的情况之一。

【问题讨论】:

使用AddDbContext&lt;XXX&gt; 并且只配置连接字符串就足够了,不要尝试修改默认为Scoped 的服务生命周期(并且应该始终如此)。你一定有一个问题其他地方,我很确定。所以现在你甚至不知道它可能在哪里,我们可能都被这个困住了。 不要使用 Singleton 生命周期,使用 Scoped 甚至 Transient,具体取决于您在代码中的使用方式 可能重复:***.com/q/66531676/264697 @KingKing 这是一个非常大的项目,但如果我想在遇到这个问题时总结一下,就变成这样:我在 EF 生成的部分类旁边制作了一些部分类。在我的课程中,我尝试执行不同的功能,例如一些复杂的查询和简单的查询,例如直接由 linq 甚至 SP 进行更新。在控制器中,如果我没有在构造函数中使用 dbcontext 创建部分类的新对象,我会遇到此错误。看来他们总是需要新鲜的 dbcontext! 感谢@KingKing 的回复 【参考方案1】:

在 asp.net 核心中,DbContext 应该是 Scoped 服务,而不是 Singleton。

改变这个:

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY"))
                .ServiceLifetime.Singleton);

services.AddDbContext<XXX>
                (option => 
                option.UseSqlServer(Configuration.GetConnectionString("YYY")));

【讨论】:

不需要添加 ServiceLifetime.Scoped 吗?我应该删除 UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) AddDbContext 将其创建为 Scoped 服务。其他选项由您决定。 对我的代码进行了一些更改并使用@kingking 建议我现在没有错误【参考方案2】:

我收到此错误是因为我没有在控制器方法内的方法上使用 await。这导致函数在调用完成之前返回并释放上下文。

【讨论】:

我有一个类似的场景,您在数据库保存上进行了等待调用。然后,在一次良好的保存之后,代码会进行另一次保存。正如您的示例所示,我忘记等待第二次数据库调用。谢谢!

以上是关于无法访问已释放的上下文实例 EF 核心的主要内容,如果未能解决你的问题,请参考以下文章

如何从我的 ASP.NET Core 5 Web 应用程序中的 SignalR 操作中解决错误“无法访问已释放的上下文实例”?

C# 无法访问已释放的对象

c# 无法访问已释放的对象

无法访问已释放的对象,该怎么解决

C#无法访问已释放的对象

C#Winform打印预览无法访问已释放的对象。