【问题标题】:Cannot access a disposed context instance EF core无法访问已释放的上下文实例 EF 核心
【发布时间】: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,具体取决于您在代码中的使用方式
  • @KingKing 这是一个非常大的项目,但如果我想在遇到这个问题时总结一下,就变成这样:我在 EF 生成的部分类旁边制作了一些部分类。在我的课程中,我尝试执行不同的功能,例如一些复杂的查询和简单的查询,例如直接由 linq 甚至 SP 进行更新。在控制器中,如果我没有在构造函数中使用 dbcontext 创建部分类的新对象,我会遇到此错误。看来他们总是需要新鲜的 dbcontext!
  • 感谢@KingKing 的回复

标签: c# database entity-framework asp.net-core dependency-injection


【解决方案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。这导致函数在调用完成之前返回并释放上下文。

【讨论】:

  • 我有一个类似的场景,您在数据库保存上进行了等待调用。然后,在一次良好的保存之后,代码会进行另一次保存。正如您的示例所示,我忘记等待第二次数据库调用。谢谢!
猜你喜欢
  • 2021-03-29
  • 2022-10-13
  • 2021-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多