我正在开发一个解耦的web api项目和扩展逻辑,它在扩展中分离(分离的项目,这给了我很多项目之间的共享代码),这就是为什么我正在处理数据层也解耦,它工作的一切,但唯一让我保持一切的东西是它的AppDbContext.cs
这是一个POC代码,所以你可以得到我的想法(我的问题):
AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> dbContextOptions) : base(dbContextOptions)
{
}
}
IEntity.cs
public interface IEntity<TKey>
{
TKey Id { get; set; }
}
IRepository.cs
public interface IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
IEnumerable<TEntity> GetAll();
}
GenericRepository.cs
public class GenericRepository<TEntity, TKey> : IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
private readonly AppDbContext dbContext;
public GenericRepository(AppDbContext dbContext)
{
this.dbContext = dbContext;
}
public IEnumerable<TEntity> GetAll()
{
return dbContext.Set<TEntity>().ToList();
}
}
并在组合根中注册,如下所示:
services.AddScoped(typeof(IRepository<,>), typeof(GenericRepository<,>));
正如您所看到的,我的通用存储库使用AppDbContext,但是如果在另一个名为different的项目中呢?或继承自IdentityContext,如何使我的通用存储库,DbContext独立但在启动时也可配置?
更新
我忘了提到,在某些情况下会有多个DbContext实现。
答案 0 :(得分:1)
这里最低的公因子是DbContext
。
Rafactor GenericRepository
明确依赖DbContext
public class GenericRepository<TEntity, TKey> : IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey> {
private readonly DbContext dbContext;
public GenericRepository(DbContext dbContext) {
this.dbContext = dbContext;
}
public IEnumerable<TEntity> GetAll() {
return dbContext.Set<TEntity>().ToList();
}
}
在组合根处,您将进行关联
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration["database:connectionString"]));
services.AddScoped(typeof(IRepository<,>), typeof(GenericRepository<,>));
services.AddScoped<DbContext, AppDbContext>();
在多个上下文的情况下,这需要更多的抽象。在这种情况下,我为每个上下文创建一个特定的抽象。例如IDbContext
或ILoggingContext
public interface IDbContext : IDisposable {
int SaveContext();
DbSet<TEntity> Set<TEntity>();
//...other relevant EF members, etc
}
public interface IAppDbContext : IDbContext {
}
public interface ILogDbContext : IDbContext {
}
让我的DbContext
派生类继承自与之相关的类。
public class AppDbContext : DbContext, IAppDbContext {
public AppDbContext(DbContextOptions<AppDbContext> dbContextOptions) : base(dbContextOptions) {
}
}
public class LogDbContext : DbContext, ILogDbContext {
public AppDbContext(DbContextOptions<LogDbContext> dbContextOptions) : base(dbContextOptions) {
}
}
从那里,通用存储库将明确依赖于相关的抽象
public class GenericRepository<TEntity, TKey> : IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey> {
private readonly IDbContext dbContext;
public GenericRepository(IAppDbContext dbContext) {
this.dbContext = dbContext;
}
//...code removed for brevity
}
然后在组合根目录下进行必要的配置。
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration["database:appConnectionString"]));
services.AddDbContext<LogDbContext>(options =>
options.UseSqlServer(Configuration["database:logConnectionString"]));
services.AddScoped(typeof(IRepository<,>), typeof(GenericRepository<,>));
services.AddScoped<IAppDbContext, AppDbContext>();
services.AddScoped<ILogDbContext, LogDbContext>();
答案 1 :(得分:0)
我找到了一个更简单的解决方案(但不是更干净)。请注意,我实际上反对将存储库模式用于EF。
Startup.cs
services.AddDbContext<context1>(options => options.UseSqlServer(Connection1), ServiceLifetime.Scoped);
services.AddDbContext<context2>(options => options.UseSqlServer(DbConnection2), ServiceLifetime.Scoped);
// Build an intermediate service provider
var sp = services.BuildServiceProvider();
services
.AddScoped<IGenericRepository<Repository.Models.SubmissionEntry>>(_ => new GenericRepository<SomeSpecificModelThatUsesContext2>(sp.GetService<context2>(), true))
.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>))
GenericRepository.cs
just add second constructor
private readonly DbContext dbContext;
public GenericRepository(context1 ctx)
{dbContext=ctx}
public GenericRepository(context2 ctx, bool fakeParamToAddSecondConstructor)
{dbContext=ctx}