DbContext对象已被处置:如何防止该对象被处置

本文关键字:对象 何防止 DbContext | 更新日期: 2023-09-27 18:08:52

我使用asp.net mvc, Entityframework 6和Unity的DI场景。

我无法找出为什么我的DbContext对象被过早地处置。

我将GenericWoU类注入到PeopleController类中。当我调用ListPerson动作一切工作正常,但是DbContext被处置。因此,如果我尝试编辑列表中的任何人,将出现以下错误:

操作无法完成,因为DbContext已经被创建处理

我怎么能防止DbContext这么早被处置?

这是我的Generic Unit of Work类:

    public class GenericUoW : IDisposable, IGenericUoW
    {
        private readonly DbContext entities = null;
        public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
        public GenericUoW(DbContext entities)
        {
            this.entities = entities;
        }
    public IRepository<T> Repository<T>() where T : class
    {
        if (repositories.Keys.Contains(typeof(T)) == true)
        {
            return repositories[typeof(T)] as IRepository<T>;
        }
        IRepository<T> repo = new GenericRepository<T>(entities);
        repositories.Add(typeof(T), repo);
        return repo;
    }
    public void SaveChanges()
    {
        entities.SaveChanges();
    }
    private bool disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                entities.Dispose();
            }
        }
        this.disposed = true;
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

这是我的GenericRepository课程:

class GenericRepository<T> : IRepository<T> where T : class
{
    private readonly DbContext entities = null;
    private DbSet<T> _objectSet;
    public GenericRepository(DbContext _entities)
    {
        entities = _entities;
        _objectSet = entities.Set<T>();
    }
    public IEnumerable<T> GetAll(Func<T, bool> predicate = null)
    {
        if (predicate != null)
        {
            return _objectSet.Where(predicate);
        }
        return _objectSet.AsEnumerable();
    }
    public T Get(Func<T, bool> predicate)
    {
        return _objectSet.First(predicate);
    }
    public void Add(T entity)
    {
        _objectSet.Add(entity);
    }
    public void Attach(T entity)
    {
        _objectSet.Attach(entity);
    }
    public void Delete(T entity)
    {
        _objectSet.Remove(entity);
    }
}

这是我的ContainerBootstrapper类:

public class ContainerBootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        return container;
    }
    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
        DbContext entities = new TeijonStuffEntities();
        container.RegisterInstance(entities);
        GenericUoW GUoW = new GenericUoW(entities);
        container.RegisterInstance(GUoW);
        MvcUnityContainer.Container = container;
        return container;
    }
}

DbContext对象已被处置:如何防止该对象被处置

一般的问题是您的组件通过处置依赖项来获得它的所有权。组件永远不知道其依赖项的生命周期是什么,以及它们以后是否会被其他组件使用(甚至可能在同一个请求中)。因此,这使得处理依赖项变得危险(甚至是完全错误的)。

相反,作为一般的经验法则,它是创建组件的人,负责其处置。因为在你的例子中,Unity创建了那个对象,它应该处理它(它会)。

这意味着您应该从GenericUoW中删除所有的dispose功能。这不仅是唯一正确的方法,而且实际上需要维护的代码要少得多,因为这不仅影响GenericUoW,而且还影响GenericUoW的所有可能的直接和间接消费者。在你的设计中,它们都必须实现IDisposable。当正确应用DI时,可以忽略这一点,这会对代码的可维护性产生巨大影响。

长话短说,将GenericUoW更改为:

public sealed class GenericUoW : IGenericUoW
{
    private readonly Dictionary<Type, object> repositories =new Dictionary<Type, object>();
    private readonly DbContext entities;
    public GenericUoW(DbContext entities)
    {
        this.entities = entities;
    }
    public IRepository<T> Repository<T>() where T : class
    {
        if (!repositories.Keys.Contains(typeof(T))) {
            IRepository<T> repo = new GenericRepository<T>(entities);
            repositories.Add(typeof(T), repo);
        }
        return (IRepository<T>)repositories[typeof(T)];
    }
    public void SaveChanges() {
        entities.SaveChanges();
    }
}