ASP.NET Core+EF Core中多DbContext(SQL Server)无法共存问题
你遇到的问题核心是先注册的DbContext无法找到对应数据库中的表,仅最后注册的DbContext可正常工作,报错Invalid object name '[TABLE_NAME]'。结合你的场景(同命名空间下的两个DbContext、实体位于同一领域项目但分属不同命名空间),最可能的原因是EF Core的模型缓存键冲突:EF Core默认基于DbContext类型全名生成模型缓存键,若两个DbContext在同一命名空间下,可能出现缓存键逻辑冲突,导致后注册的DbContext模型覆盖先注册的,最终先注册的DbContext使用错误的模型映射执行查询。
以下是几种可行的解决方法,按优先级排序:
1. 为每个DbContext设置唯一模型缓存键
显式指定每个DbContext的模型缓存键,彻底避免缓存冲突:
public class HrDbContext : DbContext { public HrDbContext(DbContextOptions<HrDbContext> options) : base(options) { } public DbSet<Employee> Employees => Set<Employee>(); // other DbSets... protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.ApplyConfiguration(new EmployeeConfiguration()); // other entity configurations } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); // 使用DbContext类名作为唯一缓存键 optionsBuilder.UseModelCacheKey(nameof(HrDbContext)); } }
对DocumentLibraryDbContext做同样配置:
public class DocumentLibraryDbContext : DbContext { public DocumentLibraryDbContext(DbContextOptions<DocumentLibraryDbContext> options) : base(options) { } public DbSet<Document> Documents => Set<Document>(); // other DbSets... protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // 对应实体配置 } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseModelCacheKey(nameof(DocumentLibraryDbContext)); } }
2. 限制DbContext的实体扫描范围
禁用EF Core的自动实体发现,仅手动注册当前DbContext需要的实体配置,避免扫描到其他命名空间的实体:
public class HrDbContext : DbContext { public HrDbContext(DbContextOptions<HrDbContext> options) : base(options) { } public DbSet<Employee> Employees => Set<Employee>(); // other DbSets... protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // 禁用自动发现非显式注册的实体 builder.Model.RemoveAnnotation("Relational:AllQueriesHaveToBeMappedToEntityTypes"); // 仅注册当前DbContext的实体配置 builder.ApplyConfiguration(new EmployeeConfiguration()); // other entity configurations } }
3. 验证连接字符串注入正确性
先确认两个DbContext是否注入了正确的连接字符串,避免因变量赋值导致的配置错误:
在测试代码中添加连接字符串输出:
public async Task OnGet() { // 输出连接字符串验证 var hrConn = hrDbContext.Database.GetConnectionString(); var docConn = documentLibraryDbContext.Database.GetConnectionString(); Console.WriteLine($"HR数据库连接字符串: {hrConn}"); Console.WriteLine($"文档库数据库连接字符串: {docConn}"); var doc = await documentLibraryDbContext.Documents.OrderBy(x => x.Id).FirstOrDefaultAsync(); var employee = await hrDbContext.Employees.OrderBy(x => x.Id).FirstOrDefaultAsync(); }
若连接字符串错误,检查DI配置中connectionString变量的赋值顺序,确保每个DbContext配置时使用的是对应数据库的连接字符串。
4. 确认DbContext构造函数的泛型参数
确保每个DbContext的构造函数使用泛型版本的DbContextOptions<TContext>,而非非泛型的DbContextOptions,保证DI能正确注入对应配置:
// 正确写法 public class HrDbContext : DbContext { public HrDbContext(DbContextOptions<HrDbContext> options) : base(options) { } }
修改后重新运行测试代码,若先注册的DbContext查询正常执行,则说明问题已解决。
内容的提问来源于stack exchange,提问作者Rick

