由于已经处理了DbContext,因此无法完成操作 - LifestylePerWcfOperation

时间:2015-04-22 15:51:36

标签: entity-framework dependency-injection castle-windsor dbcontext unit-of-work

我有一个WCF Web服务,目前遇到一些并发问题。目前负荷很小,但预计在未来几天会增加很多。

整体设置是WCF,实体框架6,依赖注入(Castle Windsor),UnitOfWork&存储库模式。

我设置了一个压力测试,并行地检查服务,我可以重新创建并发错误,例如......

  • 提交数据库事务时报告了错误,但无法确定数据库服务器上的事务是成功还是失败。
  • 已成功提交对数据库的更改,但更新对象上下文时发生错误。 ObjectContext可能处于不一致状态。内部异常消息:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的。

  • 属性“ID”是对象密钥信息的一部分,无法修改。

从我所做的研究中,看起来我应该用LifestylePerWcfOperation注入我的DbContext。目前正在使用LifestyleTransient。

当我切换到LifestylePerWcfOperation并重新运行测试时,我每次都会得到这个:

  • 由于DbContext已被处理
  • ,因此无法完成操作

所以我真的有两个问题:

  1. 我是否认为对此的真正解决方案是将我的DbContext切换为LifestylePerWcfOperation?
  2. 如果是这样,为什么我的DbContext会被吞噬呢?
  3. 以下是一些代码:

    AppStart.cs:

    IocContainer.AddFacility<TypedFactoryFacility>();
    
    IocContainer.Register(Component.For<IRepositoryFactory>().AsFactory());
    
    IocContainer.Register(Component.For<IUnitOfWork>()
                                   .ImplementedBy<UnitOfWork>)
                                 /*.LifestylePerWcfOperation()*/);
    
    IocContainer.Register(Component.For(typeof(IDbContext))
                                   .ImplementedBy(dbContextType)
                                   .DependsOn(Dependency.OnValue("connectionString", String.Format(ConfigurationManager.ConnectionStrings["---"].ConnectionString))));
                                 /*.LifestylePerWcfOperation()*/
    
    IocContainer.Register(Component.For(typeof(IRepository<>))
                                   .ImplementedBy(typeof(Repository<>))
                                   .LifestyleTransient()
                                 /*.LifestylePerWcfOperation()*/);
    
    // Register the actual dbContextType so consuming applications can access it without an interface
    IocContainer.Register(Component.For(dbContextType)
                                   .Named(dbContextType.Name)
                                   .DependsOn(Dependency.OnValue("connectionString", String.Format(ConfigurationManager.ConnectionStrings["----"].ConnectionString)));
                                 /*.LifestylePerWcfOperation()*/
    

    UnitOfWork.cs:

    public class UnitOfWork : IUnitOfWork
    {
        private readonly IDbContext _dbContext;
        private bool _disposed;
    
        public UnitOfWork(IDbContext dbContext)
        {
            _dbContext = dbContext;
        }
    
        public int Commit()
        {
            return _dbContext.SaveChanges();
        }
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _dbContext.Dispose();
                }
    
                _disposed = true;
            }
        }
    }
    

    Repository.cs

    public class Repository<T> : IRepository<T> where T : class
    {
        private readonly IDbSet<T> _dbset;
    
        public Repository(IDbContext dbContext)
        {
            _dbset = dbContext.Set<T>();
        }
    
        public IQueryable<T> Query()
        {
            return _dbset.AsQueryable();
        }
    
        public virtual IEnumerable<T> GetAll()
        {
            return _dbset.AsEnumerable();
        }
    
        public virtual void Add(T entity)
        {
            _dbset.Add(entity);
        }
    
        public virtual void Delete(T entity)
        {
            _dbset.Remove(entity);
        }
    
        public virtual void Delete(ICollection<T> entities)
        {
            entities.ToList().ForEach(Delete);
        }
    }
    

    如果需要,我可以添加更多代码。感谢您提供的任何帮助!!

2 个答案:

答案 0 :(得分:1)

回答你的问题:

1)将生活方式改为LifestylePerWcfOperation

是正确的

2)您正在UnitOfWork中部署DBContext。 DBContext由Windsor注入,因此Windsor将在其上调用Dispose。当使用windsor从不处理注入的对象时,只有使用工厂或Resolve创建对象时才必须释放(不处置)对象,因此Windsor可以处理它。

我希望使用LifeStylePerWcfOperations并删除Dispose代码,代码应运行正常。

祝你好运, Marwijn。

答案 1 :(得分:0)

我能够解决这个问题。

修复正是Marwijn所说的。解决之后,我仍然遇到类似的错误。

最后的解决方法是每次注册并使其成为LifestylePerWcfOperation。我注册了一些使用寿命较短的对象,因此DbContext也被处理掉了这些对象。

如果有人收到此错误,并且您正在使用Castle / EF,请不要明确处理DbContext(让Castle执行此操作)并制作所有LifestylePerWcfOperation。那应该解决它。然后返回并有选择地重置您不希望成为LifestylePerWcfOperation的任何物品的生活方式,并确保它不会随着时间的推移而中断。