EF4.1 Code First DbContext:由于已经处理了DbContext,因此无法完成操作

时间:2012-09-14 12:53:25

标签: c# asp.net-mvc entity-framework-4.1 unity-container dbcontext

我有一个直接调用的控制器动作,但抛出了这个错误:

The operation cannot be completed because the DbContext has been disposed.

我只在网上找到有关延期执行的解决方案,但我认为这不适用于此,因为我在任何地方使用上下文(在本例中)我都会调用.ToList().FirstOrDefault()。这是我的代码:

控制器内容

    private IUnitOfWork UnitOfWork;
    public MyFavouritesController(
        IAccountServices accountServices,
        IUnitOfWork unitOfWork
        )
    {
        AccountServices = accountServices;
        UnitOfWork = unitOfWork;
    }

    public ActionResult Index()
    {
        int? id = AccountServices.GetCurrentUserId();
        if (!id.HasValue)
        {
            return RedirectToAction("Login", "Account", new { ReturnUrl = this.HttpContext.Request.Url.AbsolutePath });
        }
        var user = UnitOfWork.UserRepo.Get(id.Value, "Favourites", "Favourites.County", "Favourites.Country");
        //THE ABOVE CALL GETS THE ERROR

        //.....
        return View();
    }

REPOSITORY BASE CLASS

public class RepositoryBase<C, T> : IDisposable
    where C:DbContext, new()
    where T : ModelBase
{
    private DbContext _context;
    public DbContext Context
    {
        get
        {
            if (_context == null)
            {
                _context = new C();
                this.AllowSerialization = true;
            }
            return _context;
        }
        set
        {
            _context = value;
        }
    }

    public virtual T Get(int Id, params string[] includes)
    {
        if (Id > 0)
        {
            var result = Context.Set<T>().Where(t => t.Id == Id);
            foreach (string includePath in includes)
            {
                result = result.Include(includePath);
            }
            return result.FirstOrDefault(); //This is where the error occurs.
        }
        else
        {
            throw new ApplicationException("Id is zero (0).");
        }
    }

    //... (More CRUD methods)

    public void Dispose()
    {
        if (Context != null)
        {
            Context.Dispose(); //Debugger never hits this before the error
        }
    }
}

工作单位

public class UnitOfWork:IUnitOfWork
{
    public UnitOfWork(
        //... DI of all repos
        IUserRepository userRepo
        )
    {
        //... save repos to an local property
        UserRepo = userRepo;

        //create a new instance of the context so that all the repo's have access to the same DbContext
        Context = new Context();

        //assign the new context to all the repo's
        //...
        UserRepo.Context = Context;
    }

    public Context Context { get; set; }

    public IUserRepository UserRepo { get; set; }

    //... (some more repositories)

    public void Dispose()
    {
        Context.Dispose(); //THIS IS NOT HIT AT ALL
    }
}

最后,模型容器有这条线

_Instance.RegisterType<IUnitOfWork, UnitOfWork>(new PerThreadLifetimeManager());

如您所见,索引操作将接收包含新DbContext对象的UnitOfWork的新实例。但是在第一次调用此上下文时,它会引发上述错误。此模式适用于我的代码中的其他位置。

由于

更新

以下答案是使用perRequestLifetimeManager。这是一个统一的实施:

    public class HttpRequestLifetimeManager : LifetimeManager
    {
        private string _key = Guid.NewGuid().ToString();

        public override object GetValue()
        {
            if (HttpContext.Current != null && HttpContext.Current.Items.Contains(_key))
                return HttpContext.Current.Items[_key];
            else
                return null;
        }

        public override void RemoveValue()
        {
            if (HttpContext.Current != null)
                HttpContext.Current.Items.Remove(_key);
        }

        public override void SetValue(object newValue)
        {
            if (HttpContext.Current != null)
                HttpContext.Current.Items[_key] = newValue;
        }
    }

2 个答案:

答案 0 :(得分:2)

我注意到您正在使用PerThreadLifetimeManager来控制工作单元的创建和处理。如果您的IoC容器支持,则应该将其更改为PerRequestLifetimeManager

答案 1 :(得分:0)

因为您正在处理工作单元,在您请求数据后,在查询后将数据存储在变量中,然后您也可以释放工作单元实例。