实体框架 创建模型时无法使用上下文

Posted

技术标签:

【中文标题】实体框架 创建模型时无法使用上下文【英文标题】: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);
    

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

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

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

【讨论】:

以上是关于实体框架 创建模型时无法使用上下文的主要内容,如果未能解决你的问题,请参考以下文章

无法为“ApplicationUser”创建 DbSet,因为此类型未包含在上下文模型中

DbContext.set() 无法为实体创建 DbSet,因为此类型未包含在上下文的模型中

应用程序无法搭建项目

实体框架在运行时创建多个表 C#

无法查看实体 - 实体框架的数据模型

无法为实体框架6使用MySQL连接