无法可靠地查询 EntityFramework 共享 dbcontext

发布于 2024-12-08 16:18:19 字数 1240 浏览 1 评论 0原文

我正在尝试在多个存储库之间共享一个带有 4 个 DbSet 的简单 DbContext,我的每个存储库都继承自该基类

 public class CodeFirstRepository : IDisposable
    {
        private static MyContext _ctx = new MyContext();
        protected MyContext Context
        {
            get { return _ctx; }
        }

        public void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
            }
        }
    }

问题:这是在存储库之间共享连接的适当方法吗?

访问各个存储库时,我的单元测试中出现间歇性失败。存储库方法 GetEntityByName 引发异常

public IOfferResult GetEntityByName(string name)
{
   return Context.Entities.Where(o => o.Name == name).FirstOrDefault()
}

测试方法 测试.服务.测试删除 抛出异常:System.ObjectDisposeException:ObjectContext 实例已被处置,不能再用于操作 需要连接。

如果数据库已存在,则代码按预期执行。当我将 GetEntityByName(string name) 的实现更改为以下非性能代码时,它也有效

public IOfferResult GetEntityByName(string name)
{
   foreach (OfferResult offer in Context.Offers)
   {
       if (offerName.ToLower() == offer.Name.ToLower())
       {
           return offer;
       }
   }
}

问题:这里发生了什么?

请记住,如果我运行测试时数据库存在,我根本不会收到错误。

蒂亚, 杰特

I'm trying to share a simple DbContext with 4 DbSets among multiple repositories, each of my repositories inherit from this base class

 public class CodeFirstRepository : IDisposable
    {
        private static MyContext _ctx = new MyContext();
        protected MyContext Context
        {
            get { return _ctx; }
        }

        public void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
            }
        }
    }

Question: is this an appropriate way to share a connection between repositories?

I'm getting intermittent failures in my unit tests when accessing the various repositories. An exception is thrown from the repository method GetEntityByName

public IOfferResult GetEntityByName(string name)
{
   return Context.Entities.Where(o => o.Name == name).FirstOrDefault()
}

Test method
Tests.Service.TestDelete
threw exception: System.ObjectDisposedException: The ObjectContext
instance has been disposed and can no longer be used for operations
that require a connection.

if the database already exists, the code executes as expected. it also works when i change the implementation of GetEntityByName(string name) to the following non-performant code

public IOfferResult GetEntityByName(string name)
{
   foreach (OfferResult offer in Context.Offers)
   {
       if (offerName.ToLower() == offer.Name.ToLower())
       {
           return offer;
       }
   }
}

Question: what is going on here?

bear in mind that if the database exists when i run the tests i don't get the error at all.

tia,
jt

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

醉城メ夜风 2024-12-15 16:18:19

出现此问题的原因是,您将 DbContext 视为单例,将其声明为静态字段,但随后通过处置它,将其视为瞬态实例一旦 CodeFirstRepository 的任何实例被释放。例如:

using (var r = new PersonRepository())
{
   // do something
} // When you hit the end of this block, your static DbContext is disposed.
using (var r = new IOfferRepository())
{
    r.GetEntityByName("test"); // this will fail because the context is still disposed.
}

您不应该以这种方式共享上下文。如果您确实希望所有存储库都使用 DbContext 的单个实例,请删除对 Context.Dispose() 的调用。这可以解决您现在遇到的问题,但将来可能会带来其他问题。

但我强烈警告不要在多个线程可能尝试同时访问单个 DbContext 的情况下使用它。根据 DbContext 规格

不保证任何实例成员都是线程安全的。

您最好从字段中删除 static 关键字。

This problem is arising because you are treating the DbContext like a singleton by declaring it as a static field, but then you are treating it like it like a transient instance by disposing it as soon as any instance of CodeFirstRepository gets disposed. For example:

using (var r = new PersonRepository())
{
   // do something
} // When you hit the end of this block, your static DbContext is disposed.
using (var r = new IOfferRepository())
{
    r.GetEntityByName("test"); // this will fail because the context is still disposed.
}

You should not share contexts this way. If you really want all of your repositories to use a single instance of the DbContext, remove the call to Context.Dispose(). This would fix the problem you're getting right now, but it will likely introduce other problems in the future.

But I would strongly caution against using a single DbContext in a scenario where multiple threads could be trying to access it simultaneously. According to the DbContext specs:

Any instance members are not guaranteed to be thread safe.

You'd be better off just removing the static keyword from your field.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文