使用ASP.NET Core控制台应用+EF6时频繁报错:模型创建时无法使用上下文
先看你遇到的错误信息:
System.InvalidOperationException: The context cannot be used while the model is being created. 若在OnModelCreating方法内使用上下文,或同一上下文实例被多线程并发访问,可能会引发此异常。请注意,DbContext及相关类的实例成员不保证线程安全。
[01/02/2018 10:59:16 > 395c4e: INFO] at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
[01/02/2018 10:59:16 > 395c4e: INFO] at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
[01/02/2018 10:59:16 > 395c4e: INFO] at System.Data.Entity.Internal.Linq.InternalSet1.Initialize() [01/02/2018 10:59:16 > 395c4e: INFO] at System.Data.Entity.Internal.Linq.InternalSet1.get_InternalContext()
[01/02/2018 10:59:16 > 395c4e: INFO] at System.Data.Entity.Infrastructure.DbQuery1.System.Linq.IQueryable.get_Provider() [01/02/2018 10:59:16 > 395c4e: INFO] at System.Linq.Queryable.Select[TSource,TResult](IQueryable1 source, Expression`1 selector)
再看你的Startup类里的依赖注入代码,问题就出在这里:
string dbConnectionString = configuration.GetValue<string>("Database:ConnectionString"); var compactDbContext = new CompactDbContext(dbConnectionString); services.AddTransient<DbContext>(dbContext => compactDbContext);
问题根源
你提前实例化了一个CompactDbContext对象,然后通过AddTransient把这个单一实例重复注入给所有请求。但EF的DbContext是非线程安全的,它的设计目标是短生命周期使用(比如每个请求/任务对应一个实例),多个线程同时访问同一个上下文实例时,就会触发这个模型创建阶段的异常——因为上下文在初始化模型的过程中,不允许被其他线程同时操作。
修复方案
修改依赖注入配置,让容器每次需要时创建一个全新的DbContext实例,而不是复用同一个对象。把上面的代码改成以下任意一种方式:
方式1:直接注入DbContext时创建新实例
string dbConnectionString = configuration.GetValue<string>("Database:ConnectionString"); services.AddTransient<DbContext>(sp => new CompactDbContext(dbConnectionString));
方式2:推荐注册具体的CompactDbContext(更清晰)
如果你的仓储类依赖的是CompactDbContext而非抽象的DbContext,可以这样注册:
string dbConnectionString = configuration.GetValue<string>("Database:ConnectionString"); services.AddTransient<CompactDbContext>(sp => new CompactDbContext(dbConnectionString)); // 如果同时需要抽象的DbContext,再添加这一行 services.AddTransient<DbContext, CompactDbContext>();
额外注意事项
- 永远不要在多线程环境下共享
DbContext实例,包括不要把它注册为Singleton(控制台应用中,通常每个任务/操作对应一个上下文实例)。 - 检查你的
OnModelCreating方法,确保没有在模型构建过程中使用当前上下文执行查询或其他操作——这也会触发同样的异常,但从你的错误栈来看,核心问题还是共享实例导致的并发冲突。 - 确保你的仓储类(比如
UserBasicInfoRepository)在构造函数中接收的是容器注入的短生命周期上下文实例,而不是手动创建的共享对象。
内容的提问来源于stack exchange,提问作者Parthi

