在同一个ASP.NET Core解决方案中,无法让两个DbContext与 EF Core和 SQL Server一起正常工作
两个 DbContext 在同一个基础设施项目中的两个独立数据库(如果这点重要,它们都在同一个命名空间内)。所有实体都在同一个领域项目中(每个数据库的实体在各自的命名空间里)。这两个数据库都没有同名的表。
尝试查询数据时的异常:
Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name '[TABLE_NAME]'
(请查看底部的调用代码)。我搜索到的结果多为关于迁移的问题(例如未创建数据库),但这是一个DB-first项目,因此没有迁移。
下面是我用于依赖注入的相关服务代码。底部那个 DbContext 的实现能工作。在这个例子中,"DocumentLibrary" 会工作,但如果把底部改成 "HR",也能工作。这似乎表明问题并非出在数据库、连接字符串或实体配置上。
connectionString = builder.Configuration.GetConnectionString("HR") ?? throw new InvalidOperationException("Connection string 'HR' not found.");
builder.Services.AddDbContext<HrDbContext>(options =>
// I've tried commenting out all the options except UseSqlServer() to narrow down the issues, but it had no effect
options
.UseSqlServer(connectionString)
.EnableDetailedErrors()
.UseLazyLoadingProxies()
);
connectionString = builder.Configuration.GetConnectionString("DocumentLibrary") ?? throw new InvalidOperationException("Connection string 'DocumentLibrary' not found.");
builder.Services.AddDbContext<DocumentLibraryDbContext>(options =>
// I've tried commenting out all the options except UseSqlServer() to narrow down the issues, but it had no effect
options
.UseSqlServer(connectionString)
.EnableDetailedErrors()
.UseLazyLoadingProxies()
);
简化的 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); // I've moved this to the top and bottom with no effect
builder.ApplyConfiguration(new EmployeeConfiguration());
// other entity configurations
}
}
简化的示例实体配置:
public class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
{
public void Configure(EntityTypeBuilder<Employee> builder)
{
builder.HasKey(pk => pk.Id);
builder.ToTable("Employee");
// other configurations
}
}
异常发生的测试页面:
// This is just a test for working through this issue. I know injecting a DbContext into a page is generally bad practice.
public class DbContextTestModel(HrDbContext hrDbContext, DocumentLibraryDbContext documentLibraryDbContext) : PageModel
{
public async Task OnGet()
{
// works when it's the last DbContext declared, fails if it's first
var doc = await documentLibraryDbContext.Documents.OrderBy(x => x.Id).FirstOrDefaultAsync();
// works when it's the last DbContext declared, fails if it's first
var employee = await hrDbContext.Employees.OrderBy(x => x.Id).FirstOrDefaultAsync();
}
}
解决方案
问题在于对 connectionString 变量的重复使用。由于它在回调操作中被使用,不能保证第一次回调在第二次赋值之前发生。 (事实上很可能不会发生。)
为说明如下:
// This happens FIRST
connectionString = builder.Configuration.GetConnectionString("HR") ?? throw new InvalidOperationException("Connection string 'HR' not found.");
builder.Services.AddDbContext<HrDbContext>(options =>
// This happens THIRD
options
.UseSqlServer(connectionString)
.EnableDetailedErrors()
.UseLazyLoadingProxies()
);
// This happens SECOND
connectionString = builder.Configuration.GetConnectionString("DocumentLibrary") ?? throw new InvalidOperationException("Connection string 'DocumentLibrary' not found.");
builder.Services.AddDbContext<DocumentLibraryDbContext>(options =>
// This happens FOURTH
options
.UseSqlServer(connectionString)
.EnableDetailedErrors()
.UseLazyLoadingProxies()
);
这符合这样的模式:后者的连接总是能工作。因为前者最终使用了错误的连接字符串。
只需使用一个不同的变量:
// Self-contained HR connection
var hrConnectionString = builder.Configuration.GetConnectionString("HR") ?? throw new InvalidOperationException("Connection string 'HR' not found.");
builder.Services.AddDbContext<HrDbContext>(options =>
options
.UseSqlServer(hrConnectionString)
.EnableDetailedErrors()
.UseLazyLoadingProxies()
);
// Self-contained DocumentLibrary connection
var dlConnectionString = builder.Configuration.GetConnectionString("DocumentLibrary") ?? throw new InvalidOperationException("Connection string 'DocumentLibrary' not found.");
builder.Services.AddDbContext<DocumentLibraryDbContext>(options =>
options
.UseSqlServer(dlConnectionString)
.EnableDetailedErrors()
.UseLazyLoadingProxies()
);
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。