【问题标题】:How to use a dbcontext in a static class? (ObjectDisposedException)如何在静态类中使用 dbcontext? (ObjectDisposedException)
【发布时间】:2018-03-08 00:13:05
【问题描述】:

嘿,我最近刚刚学会了如何使用扩展方法,很高兴能在我当前的项目中实现它。

我的目标: 我想检查一个条目是否存在于我的表中的辅助类中,因为我将在多个控制器中使用它来确定在我的导航栏中显示哪些导航链接:

我的问题: 我不知道如何在我的静态助手类中访问我的 dbcontext。我的 dbcontext 控制器接受一个我不知道如何传入我的静态类的参数。我认为创建一个新的 dbcontext 可以解决下面解释的范围问题,但我不知道如何将可选参数传递给我的构造函数。

目前在 Startup.cs 类中配置。

我尝试了什么: 将 ApplicationDbContext 作为参数传递。这适用于我的控制器中的单个方法调用,但是当调用多个扩展方法(检查用户拥有哪些游戏帐户)时,我得到一个 ObjectDisposedException。

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

据我了解,这是一个范围问题,即第一个方法调用在完成后处理上下文,而我试图在下一次调用中使用相同的上下文?我可以做些什么来解决这个问题?

我尝试阅读此链接Cannot access a disposed of object in ASP.NET Core when injecting DbContext,但它对我没有帮助,因为它需要 Startup.cs 类中的 ApplicationBuilder。

解决方案更新 我在每次方法调用后都处理了 dbcontext,因为我将它放入了一个变量中。相反,我直接在传递的上下文中调用它并且它可以工作:

【问题讨论】:

  • 你怎么打电话 HasDota2Account()?您是否将其传递给已处理的DbContext_context 来自哪里?该错误似乎表明它确实在您调用UpdateNavLinks() 之前被处理。因此,您似乎不应该处置它,或者应该在该方法中使用本地实例化的上下文。尝试共享​​>数据上下文对象通常会导致这个问题。
  • 另外,在 HasDota2Account 中,db 是与上下文相同的对象;当 db 被 Disposed 时,上下文也会如此。如果您在调用 HasDota2Account 后尝试使用上下文,则会出现相同的异常。
  • 我从控制器调用它,就像我的第一张图片一样。 context 是我的控制器上的一个字段,在构造函数中被实例化。不知道有没有处理掉。我不认为我了解如何实例化本地 dbcontext _,因为它需要选项参数,我无法在 _of startup.cs 之外传递
  • @simonatrcl 啊,你是对的。这就是问题所在,它现在有效。我将用答案更新我的问题,如果您想获得荣誉,可以将其写在答案中,我会投票 :) 也感谢大卫!
  • @J.Kirk.: 太好了!谢谢,但不用担心分数,那些阅读问题的人可以很容易地看到 cmets。干杯!

标签: c# entity-framework extension-methods dbcontext asp.net-core-2.0


【解决方案1】:

是的,虽然这些扩展对您来说是新的和闪亮的,但这并不意味着您应该将它们用于所有事情。首先,扩展应该与它们正在操作的类型有逻辑联系。例如,如果你有一个string,那么像ToUpper() 这样的扩展名是有意义的,因为它会修改并返回一个字符串。类似于您正在尝试做的事情:仅使用引用的值来返回完全外来的类型是违反扩展模式的。

其次,扩展不应与数据库之类的东西交互。特别是在这里,扩展的静态特性与 EF 上下文对象的概念完全不兼容。你甚至可以让它工作的唯一方法是每次调用扩展时在扩展内部实际新建一个上下文。这既是搞砸 EF 对象跟踪的好方法,也是泄漏内存的好方法。

长短不一,别这样。

如果您只是想分解出这段代码,那么您有更好的选择。例如,您实际上可以直接将方法添加到您的上下文中。

public class ApplicationDbContext : DbContext
{
    ...

    public bool HasDota2Account(string id)
    {
        return Dota2Accounts.Any(m => m.ApplicationUserId == id);
    }
}

然后,在您的控制器中,您可以简单地执行以下操作:

var hasDota2Account = context.HasDota2Account(User.Identity.GetUserId());

【讨论】:

  • 感谢您的解释。每天学习新东西。
【解决方案2】:

永远不要将 DbContext 声明为静态,这会导致各种麻烦,并且不会刷新数据,因此您将从查询中获取旧数据。一个选项是每次使用它时都在静态方法中实例化它,如下所示:

public static MyClass Example
{
        public static bool MyStaticMethod(long id)
        {
            MyDBContext db = new MyDBContext();
            //use db context now....
        }
}

【讨论】:

  • 更好的方法是在已处置的范围内实例化上下文,使用 using 语句:using var db = new MyDBContext();
  • 这怎么可能,这会抛出异常。
猜你喜欢
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-01
  • 1970-01-01
  • 2018-10-27
  • 2018-12-25
  • 1970-01-01
相关资源
最近更新 更多