【问题标题】:Entity Framework The context cannot be used while the model is being created实体框架 创建模型时无法使用上下文
【发布时间】:2016-01-13 18:17:44
【问题描述】:

下面提到了我的工作单元类,我正在使用 Ninject,我尝试为每个线程范围、瞬态等的每个请求注入 IUnitOfWork,但我仍然收到错误消息:

"Message":"发生错误。","ExceptionMessage":"创建模型时无法使用上下文。如果在 OnModelCreating 方法内部使用上下文或相同的上下文,则可能会引发此异常context 实例被多个线程并发访问。注意,DbContext 和相关类的实例成员不保证是线程安全的。","ExceptionType":"System.InvalidOperationException

当我使用 angularJS 同时进行两个 Web API (get) 调用时出现此错误,它在_context.Set<TEntity>().FirstOrDefault(match); 处显示错误

public class UnitOfWork : IUnitOfWork, IDisposable
{
    private My_PromotoolEntities _uowDbContext = new My_PromotoolEntities();

    private Dictionary<string, object> _repositories;


    // Do it like this if no specific class file
    private GenericRepository<MysPerson> _personRepository;
    //private GenericRepository<MysDataSource> dataSourcesRepository;
    //private GenericRepository<MysCountry> countryMasterRepository;


    // Or like this if with specific class file.
    private DataSourceRepository _dataSourcesRepository;
    private CustomerRepository _customerRepository;
    private DeviceRepository _deviceRepository;
    private DeviceRegistrationRepository _deviceRegistrationRepository;
    private EmailQueueRepository _emailQueueRepository;


    public void SetContext(My_PromotoolEntities context)
    {
        _uowDbContext = context;
    }


    public void CacheThis(object cacheThis, string keyName, TimeSpan howLong)
    {
        Cacheing.StaticData.CacheStaticData(cacheThis, keyName, howLong);
    }
    public object GetFromCache(string keyName)
    {
        return Cacheing.StaticData.GetFromCache(keyName);
    }


    public GenericRepository<T> GenericRepository<T>() where T : BaseEntity
    {
        if (_repositories == null)
        {
            _repositories = new Dictionary<string, object>();
        }

        var type = typeof(T).Name;

        if (!_repositories.ContainsKey(type))
        {
            var repositoryType = typeof(GenericRepository<>);
            var repositoryInstance = Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), _uowDbContext);
            _repositories.Add(type, repositoryInstance);
        }
        return (GenericRepository<T>)_repositories[type];
    }

    public GenericRepository<MysPerson> PersonRepository
    {
        get
        {
            if (this._personRepository == null)
            {
                this._personRepository = new GenericRepository<MysPerson>(_uowDbContext);
            }
            return _personRepository;
        }
    }
    public DataSourceRepository DataSourcesRepository
    {
        get
        {
            if (this._dataSourcesRepository == null)
            {
                this._dataSourcesRepository = new DataSourceRepository(_uowDbContext);
            }
            return _dataSourcesRepository;
        }
    }
    public CustomerRepository CustomerRepository
    {
        get
        {
            if (this._customerRepository == null)
            {
                this._customerRepository = new CustomerRepository(_uowDbContext);
            }
            return _customerRepository;
        }
    }
    public DeviceRepository DeviceRepository
    {
        get
        {
            if (this._deviceRepository == null)
            {
                this._deviceRepository = new DeviceRepository(_uowDbContext);
            }
            return _deviceRepository;
        }
    }
    public DeviceRegistrationRepository DeviceRegistrationRepository
    {
        get
        {
            if (this._deviceRegistrationRepository == null)
            {
                this._deviceRegistrationRepository = new DeviceRegistrationRepository(_uowDbContext);
            }
            return _deviceRegistrationRepository;
        }
    }

    public EmailQueueRepository emailQueueRepository
    {
        get
        {
            if (this._emailQueueRepository == null)
            {
                this._emailQueueRepository = new EmailQueueRepository(_uowDbContext);
            }
            return _emailQueueRepository;
        }
    }




    /// <summary>
    /// Commits all changes to the db. Throws exception if fails. Call should be in a try..catch.
    /// </summary>
    public void Save()
    {
        try
        {
            _uowDbContext.SaveChanges();
        }
        catch (DbEntityValidationException dbevex)
        {
            // Entity Framework specific errors:

            StringBuilder sb = new StringBuilder();
            var eve = GetValidationErrors();
            if (eve.Count() > 0)
            {
                eve.ForEach(error => sb.AppendLine(error));
            }

            ClearContext();

            // Throw a new exception with original as inner.
            var ex = new Exception(sb.ToString(), dbevex);
            ex.Source = "DbEntityValidationException";
            throw ex;
        }
        catch (Exception)
        {
            ClearContext();
            throw;
        }
    }

    private void ClearContext()
    {
        DetachAll();
    }

    private void DetachAll()
    {
        foreach (DbEntityEntry dbEntityEntry in _uowDbContext.ChangeTracker.Entries())
        {

            if (dbEntityEntry.Entity != null)
            {
                dbEntityEntry.State = EntityState.Detached;
            }
        }
    }

    /// <summary>
    /// Checks for EF DbEntityValidationException(s).
    /// </summary>
    /// <returns>Returns a List of string containing the EF DbEntityValidationException(s).</returns>
    public List<string> GetValidationErrors()
    {
        if (_uowDbContext.GetValidationErrors().Count() != 0)
        {
            return _uowDbContext.GetValidationErrors().Select(e => string.Join(Environment.NewLine, e.ValidationErrors.Select(v => string.Format("{0} - {1}", v.PropertyName, v.ErrorMessage)))).ToList();
        }
        return null;
    }



    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                _uowDbContext.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

【问题讨论】:

    标签: multithreading asp.net-web-api model-view-controller entity-framework-6


    【解决方案1】:

    您不应该同时在 2 个地方使用上下文,这正是您收到此错误的原因。来自MSDN documentation

    线程安全:这种类型的任何公共静态(在 Visual Basic 中为共享)成员都是线程安全的。 不保证任何实例成员都是线程安全的。

    【讨论】:

    • 谢谢你能解释一下我是如何在两个地方使用上下文的
    • 无法从这段代码中看出,我猜你正在注入IUnitOfWork的共享副本。
    • 我已经搜索了我的所有代码,唯一能找到参考的地方是 ninjectWebCommon,即 kernel.Bind().To();
    • 我想我找到了两个带有新初始化程序的 My_PromotoolEntities 实例让我回到你的答案让我删除其中一个
    • 即使我已将其删除,但仍因相同问题而失败
    【解决方案2】:

    在没有复制的情况下提出建议有点困难,但有一种蛮力方法可以解决问题。如果您在 DI 设置之前/期间有一个拦截点,那么您可以通过创建上下文实例并调用 ctx.Database.Initialize(force: false); 来导致所有上下文初始化等发生。传递 'force: false' 将确保每个 AppDomain 仍然只发生一次初始化

    【讨论】:

      猜你喜欢
      • 2015-11-14
      • 2016-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多