如何使仓储与工作单元通过ApplicationDbContext工厂获取BaseDbContext?
解决方案
方案1:自定义工厂包装类
由于EF Core默认的Internal.DbContextFactory<T>无法直接协变转换为IDbContextFactory<BaseDbContext>,可以通过自定义包装类实现接口适配:
1.1 实现包装类
public class BaseDbContextFactoryAdapter : IDbContextFactory<BaseDbContext> { private readonly IDbContextFactory<ApplicationDbContext> _appDbContextFactory; public BaseDbContextFactoryAdapter(IDbContextFactory<ApplicationDbContext> appDbContextFactory) { _appDbContextFactory = appDbContextFactory; } public BaseDbContext CreateDbContext() { // ApplicationDbContext继承自BaseDbContext,可直接向上转型 return _appDbContextFactory.CreateDbContext(); } }
1.2 注册依赖
在微服务的依赖注入配置中(如Program.cs),先注册ApplicationDbContext的工厂,再注册包装类作为IDbContextFactory<BaseDbContext>的实现:
// 注册ApplicationDbContext工厂,动态获取连接字符串 builder.Services.AddDbContextFactory<ApplicationDbContext>(options => { string connectionString = RetrieveConnectionString(); options.UseSqlServer(connectionString); }); // 注册适配类,为类库提供BaseDbContext工厂实例 builder.Services.AddScoped<IDbContextFactory<BaseDbContext>, BaseDbContextFactoryAdapter>();
这样类库中的Repository、UnitOfWork依赖IDbContextFactory<BaseDbContext>时,容器会注入BaseDbContextFactoryAdapter,调用CreateDbContext()将返回实际的ApplicationDbContext实例,满足继承关系要求。
方案2:泛型仓储/工作单元改造
如果允许修改类库中的Repository和UnitOfWork定义,可以将其改为泛型实现,直接依赖具体的DbContext工厂:
2.1 修改泛型仓储
public class GenericRepository<TContext> : IGenericRepository where TContext : BaseDbContext { private readonly IDbContextFactory<TContext> _dbContextFactory; public GenericRepository(IDbContextFactory<TContext> dbContextFactory) { _dbContextFactory = dbContextFactory; } // 仓储方法示例 public async Task<TEntity> GetByIdAsync<TEntity>(int id) where TEntity : class { using var context = _dbContextFactory.CreateDbContext(); return await context.Set<TEntity>().FindAsync(id); } }
2.2 注册泛型仓储
在微服务中注册时指定具体的ApplicationDbContext类型:
builder.Services.AddScoped<IGenericRepository, GenericRepository<ApplicationDbContext>>();
这种方式无需额外包装类,直接通过泛型约束绑定到具体的DbContext工厂,更符合依赖倒置原则。
方案3:直接注册工厂委托
如果不想新增类,可以通过依赖注入的工厂委托直接注册IDbContextFactory<BaseDbContext>:
builder.Services.AddDbContextFactory<ApplicationDbContext>(options => { string connectionString = RetrieveConnectionString(); options.UseSqlServer(connectionString); }); // 直接委托解析ApplicationDbContext工厂并转换为BaseDbContext工厂 builder.Services.AddScoped<IDbContextFactory<BaseDbContext>>(sp => { var appFactory = sp.GetRequiredService<IDbContextFactory<ApplicationDbContext>>(); return new BaseDbContextFactoryAdapter(appFactory); });
内容的提问来源于stack exchange,提问作者M. Ozn
相关产品推荐
相关产品推荐

