سؤال

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

هل كانت مفيدة؟

المحلول

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top