【问题标题】:Why DbContext is diposing every time?为什么 DbContext 每次都在处理?
【发布时间】:2014-07-21 07:11:31
【问题描述】:

我正在使用实体框架 6 和城堡温莎实现 UOW 和通用存储库模式。我正在关注链接 [http://blog.longle.net/2013/05/11/genericizing-the-unit-of-work-pattern-repository-pattern-with-entity-framework-in-mvc/][1]

我的代码如下:

Conceptu.Core:

数据上下文:

public interface IDataContext : IDisposable
    {
       IDbSet<TEntity> Set<TEntity>() where TEntity : class;
       int SaveChanges();
    }

域:

public interface IUnitOfWork : IDisposable
    {
        void Dispose();
        void Save();
        void Dispose(bool disposing);
        IRepository<TEntity> Repository<TEntity>() where TEntity : class;

    }


public interface IRepository<TEntity> where TEntity : class
    {

        TEntity Find(params object[] keyValues);
        int Insert(TEntity entity);
        IQueryable<TEntity> Queryable();
        IRepository<T> GetRepository<T>() where T : class;

    }

我正在 Conceptu.Data 层中实现所有这些接口:

Conceptu.Data

EFUnitOFWork:

public class EFUnitOfWork : IUnitOfWork
    {
        #region Private variable

        private readonly IDataContext _dataContext;
        private bool _disposed;
        private Dictionary<string, object> _repositories;
        private ObjectContext _objectContext;
        private DbTransaction _transaction;

        #endregion Private variable

        public EFUnitOfWork(IDataContext context)
        {
            _dataContext = context;
        }

        public EFUnitOfWork()
        {
            _dataContext = new ConceptuModelContainer();
        }

     public void Save()
    {
      if (_disposed)
          throw new ObjectDisposedException("UnitOfWork");
      _dataContext.SaveChanges();
    }
        public void Dispose()
        {
            if (_objectContext != null && _objectContext.Connection.State ==                         ConnectionState.Open)
            {
                _objectContext.Connection.Close();
            }

            Dispose(true);
            GC.SuppressFinalize(this);
        }



        public void Dispose(bool disposing)
        {
            if (_disposed) return;
            if (disposing) _dataContext.Dispose();
            _disposed = true;
        }

        public IRepository<TEntity> Repository<TEntity>() where TEntity : class
        {

            if (_repositories == null)
            {
                _repositories = new Dictionary<string, object>();
            }

            var type = typeof(TEntity).Name;

            if (_repositories.ContainsKey(type))
            {
                return (IRepository<TEntity>)_repositories[type];
            }

            var repositoryType = typeof(Repository<>);
            try
            {
                _repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _dataContext, this));
            }
            catch (Exception er)
            {
                throw er;
            }
            return (IRepository<TEntity>)_repositories[type];


        }



    }
}

Repository.cs:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {

        #region Private Fields
        private readonly IDataContext _dbContext;
        private readonly IDbSet<TEntity> _dbSet;
        private readonly IUnitOfWork _unitOfWork;
        #endregion Private Fields

        public Repository(IDataContext context, IUnitOfWork unitOfWork)
        {
            _dbContext = context;
            _dbSet = context.Set<TEntity>();
            _unitOfWork = unitOfWork;



        }
      public virtual int Insert(TEntity entity)
        {
            try
            {
                  _dbSet.Add(entity);
                return _dbContext.SaveChanges();
            }


            catch (Exception er)
            {

                var error = er.InnerException.InnerException as Exception;
                throw error;
            }


        }





        public IQueryable<TEntity> Queryable() { return _dbSet; }


        public IRepository<T> GetRepository<T>() where T : class
        {
            return _unitOfWork.Repository<T>();
        }

        internal IQueryable<TEntity> Select(
          Expression<Func<TEntity, bool>> filter = null,
          Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
          List<Expression<Func<TEntity, object>>> includes = null,
          int? page = null,
          int? pageSize = null)
        {
            IQueryable<TEntity> query = _dbSet;

            if (includes != null)
            {
                query = includes.Aggregate(query, (current, include) => current.Include(include));
            }
            if (orderBy != null)
            {
                query = orderBy(query);
            }
            if (filter != null)
            {
                query = query.AsExpandable().Where(filter);
            }
            if (page != null && pageSize != null)
            {
                query = query.Skip((page.Value - 1) * pageSize.Value).Take(pageSize.Value);
            }
            return query;
        }
    }

BootStrapper.cs

public class Bootstrapper
    {

       public static void Initialise()
       {
           IWindsorContainer _container = new WindsorContainer();
           _container.Kernel.Register(Component.For<IDataContext>().ImplementedBy<ConceptuModelContainer>());
           _container.Kernel.Register(Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>());
           //IoC.Container.Register(typeof(IDataContext), typeof(ConceptuModelContainer));
           //IoC.Container.Register(typeof(IUnitOfWork), typeof(EFUnitOfWork));


       }
    }

服务层:我从 wcf 层调用它

我正在从服务层调用存储库

public class CompanyService : ICompanyService
    {
        #region Private fields
        private readonly IRepository<Company> _companyRepository;

        #endregion

        #region Constructor

        public CompanyService(IRepository<Company> companyRepository)
        {
            _companyRepository = companyRepository;
        }
       _companyRepository.Insert(_objcompany);

    }



[ServiceContract]
    public interface ICompanyService
    {
          [OperationContract]
         int SaveCompany(CompanyRequest _objCompanyRequest);
    }

在 Global.asax.cs 我为注册而写的

IWindsorContainer _container;

    protected void Application_Start(object sender, EventArgs e)
    {

        _container = new WindsorContainer();
        _container.AddFacility<WcfFacility>().Register(

            Component.For<IDataContext>().ImplementedBy<ConceptuModelContainer>().LifestylePerWebRequest(),
            Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>().LifestylePerWebRequest(),
            Component.For(typeof(IRepository<>)).ImplementedBy(typeof(Repository<>)).LifestylePerWebRequest(),

            Component.For<ICompanyService>().ImplementedBy<CompanyService>      ().Named("Conceptu.Services.CompanyService.CompanyService")
            );

    }

但我的问题是,当我使用 wcf 服务调用 Save 时,会抛出错误。错误显示 DBContext 已被释放。

【问题讨论】:

  • 请仅发布与您的问题相关的代码。没有人会阅读所有这些东西
  • 为了更好地理解,我已经给出了所有代码 bcoz 我无法理解哪里出错了
  • @Joydip 我明白这一点,但这使得这个问题不适合 Stack Overflow。这不是代码审查网站。问题应简明扼要,并在合理的时间内回答。
  • 好的,我尝试最小化代码
  • 你展示了两个不同的地方,你用 Windsor 容器注册你的 IDataContext 和 IUnitOfWork。只有 Application Start 中的那个显示了 LifestylePerWebRequest 配置。为什么你有一个引导程序和应用程序启动?

标签: entity-framework wcf design-patterns castle-windsor


【解决方案1】:
Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>().LifestylePerWebRequest()
  • 您通过工作单元处理每个请求的上下文,因为您已在 IoC 中注册它,即使您没有在 UoW 中明确处理它。为了证明您可以在 dispose 中放置一个断点,并在 Castle 调用 Dispose 时查看调用堆栈。
  • 您通过工厂将上下文带到 UoW。更好的方法是将编译后的模型存储在缓存中,这样您就不会在每个请求上为上下文生成模型。

这是一个模型存储的示例实现,您可以根据需要对其进行修改:

public class DefaultDbModelStore : IDbModelStore
{
    private readonly IDbModelBuilder _modelBuilder;
    private readonly Dictionary<string, IDbModel> _modelsDict;

    public DefaultDbModelStore(IDbModelBuilder modelBuilder)
    {
        _modelBuilder = modelBuilder;
        _modelsDict = new Dictionary<string, IDbModel>();
    }

    public IDbModel GetModel(string moduleName)
    {
        if (moduleName == null) { 
            moduleName = string.Empty; 
        }
        //TODO: Try using ReaderWriterLockSlim for improved performance
        lock (_modelsDict)
        {
            IDbModel result;
            if (!_modelsDict.TryGetValue(moduleName, out result))
            {
                result = _modelBuilder.BuildModel(moduleName);
                _modelsDict.Add(moduleName, result);
            }
            return result;
        }
    }
}

有一个 DbContext 的构造函数接受编译后的模型。

【讨论】:

  • 感谢您的建议。请给出如何将上下文放入缓存的解决方案。
  • 对不起。这是一个错误。缓存的是编译后的模型,而不是上下文本身。对于 dbContext,我能想到的最多的就是将其设置为范围或每个 Web 请求。你可以看到如何编译 DbModel 并缓存它here。缓存大对象模型的 dbCompiled 模型会为你节省很多时间,因为它每次都会被编译。
  • @Joydip 如果您需要更高的性能,您可以进一步探索二级缓存here 的可能性。
猜你喜欢
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多