使用通用 dbContext(多个 dbContext)获取通用存储库
Getting generic repository with generic dbContext (multiple dbContext)
我在使用 entity framework 构建通用存储库时迷路了,它在我的 asp.net 核心 2 api 项目中有多个上下文。
我需要的是在不知道它使用哪个上下文的情况下将我的存储库注入控制器。
DbContext
public interface IDbContext
{
}
public interface IBlogContext : IDbContext
{
}
public interface IBlogLogContext : IDbContext
{
}
存储库
public class EfRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
private readonly IDbContext _context;
private readonly DbSet<TEntity> _dbSet;
public EfRepository(IDbContext context)
{
_context = context;
_dbSet = _context.Set<TEntity>();
}
/* other stuff */
}
启动
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BlogContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
.UseLoggerFactory(_logger);
});
services.AddDbContext<BlogLogContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
services.AddScoped<IBlogContext, BlogContext>();
services.AddScoped<IBlogLogContext, BlogLogContext>();
services.AddUnitOfWork<BlogContext, BlogLogContext>();
}
控制器
public class UserController : Controller
{
private readonly IRepository<User> _repository;
private readonly IAuthorService _authorService;
private readonly ILogger<UserController> _logger;
public UserController(IRepository<User> repository, IAuthorService authorService, ILogger<UserController> logger)
{
_repository = repository;
_authorService = authorService;
_logger = logger;
}
}
当我在控制器构造函数中注入IRepository<User>
时,.net core DI如何解析User
是BlogContext
的实体,所以IDbContext
应该是BlogContext
在我的 EfRepository
实现中?
我用 DbContext 通用参数定义了我的 EfRepository,如下所示:
public class EfRepository<TDbContext, TEntity> : IRepository<TEntity>
where TDbContext : DbContext
where TEntity : class, IEntity
{
public EfRepository(IDbContextProvider<TDbContext> dbContextProvider)
{
}
}
并获得了这样的 DbContext-Entity 信息:
//EntityTypeInfo is a class has EntityType & DeclaringType props
private IList<EntityTypeInfo> GetEntityTypeInfos()
{
var result = new List<EntityTypeInfo>();
var dbContextTypes = this.GetType().Assembly.GetTypes().Where(t => (typeof(DbContext).IsAssignableFrom(t)));
foreach (var dbContextType in dbContextTypes)
{
result.AddRange(
from property in dbContextType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where
Common.IsAssignableToGenericType(property.PropertyType, typeof(DbSet<>)) &&
Common.IsAssignableToGenericType(property.PropertyType.GenericTypeArguments[0], typeof(IEntity))
select new EntityTypeInfo(
property.PropertyType.GenericTypeArguments[0],
property.DeclaringType
);
}
return result;
}
所以我可以使用 EntityTypeInfo 列表添加相关服务:
var entityTypeInfos = GetEntityTypeInfos();
foreach (var entityTypeInfo in entityTypeInfos)
{
//
//Add IDbContextProvider and DbContext services Here
//
//Add IRepository services like this
var repositoryInterface =typeof(IRepository<>);
var repositoryImplementation =typeof(EfRepository<,>);
var genericRepositoryType = repositoryInterface.MakeGenericType(entityTypeInfo.EntityType);
if (!Common.IocHasRegister(genericRepositoryType))
{
var implRepositoryType = repositoryImplementation.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType);
services.AddScoped(genericRepositoryType, implRepositoryType);
}
}
我在使用 entity framework 构建通用存储库时迷路了,它在我的 asp.net 核心 2 api 项目中有多个上下文。
我需要的是在不知道它使用哪个上下文的情况下将我的存储库注入控制器。
DbContext
public interface IDbContext
{
}
public interface IBlogContext : IDbContext
{
}
public interface IBlogLogContext : IDbContext
{
}
存储库
public class EfRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity
{
private readonly IDbContext _context;
private readonly DbSet<TEntity> _dbSet;
public EfRepository(IDbContext context)
{
_context = context;
_dbSet = _context.Set<TEntity>();
}
/* other stuff */
}
启动
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BlogContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
.UseLoggerFactory(_logger);
});
services.AddDbContext<BlogLogContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
services.AddScoped<IBlogContext, BlogContext>();
services.AddScoped<IBlogLogContext, BlogLogContext>();
services.AddUnitOfWork<BlogContext, BlogLogContext>();
}
控制器
public class UserController : Controller
{
private readonly IRepository<User> _repository;
private readonly IAuthorService _authorService;
private readonly ILogger<UserController> _logger;
public UserController(IRepository<User> repository, IAuthorService authorService, ILogger<UserController> logger)
{
_repository = repository;
_authorService = authorService;
_logger = logger;
}
}
当我在控制器构造函数中注入IRepository<User>
时,.net core DI如何解析User
是BlogContext
的实体,所以IDbContext
应该是BlogContext
在我的 EfRepository
实现中?
我用 DbContext 通用参数定义了我的 EfRepository,如下所示:
public class EfRepository<TDbContext, TEntity> : IRepository<TEntity>
where TDbContext : DbContext
where TEntity : class, IEntity
{
public EfRepository(IDbContextProvider<TDbContext> dbContextProvider)
{
}
}
并获得了这样的 DbContext-Entity 信息:
//EntityTypeInfo is a class has EntityType & DeclaringType props
private IList<EntityTypeInfo> GetEntityTypeInfos()
{
var result = new List<EntityTypeInfo>();
var dbContextTypes = this.GetType().Assembly.GetTypes().Where(t => (typeof(DbContext).IsAssignableFrom(t)));
foreach (var dbContextType in dbContextTypes)
{
result.AddRange(
from property in dbContextType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where
Common.IsAssignableToGenericType(property.PropertyType, typeof(DbSet<>)) &&
Common.IsAssignableToGenericType(property.PropertyType.GenericTypeArguments[0], typeof(IEntity))
select new EntityTypeInfo(
property.PropertyType.GenericTypeArguments[0],
property.DeclaringType
);
}
return result;
}
所以我可以使用 EntityTypeInfo 列表添加相关服务:
var entityTypeInfos = GetEntityTypeInfos();
foreach (var entityTypeInfo in entityTypeInfos)
{
//
//Add IDbContextProvider and DbContext services Here
//
//Add IRepository services like this
var repositoryInterface =typeof(IRepository<>);
var repositoryImplementation =typeof(EfRepository<,>);
var genericRepositoryType = repositoryInterface.MakeGenericType(entityTypeInfo.EntityType);
if (!Common.IocHasRegister(genericRepositoryType))
{
var implRepositoryType = repositoryImplementation.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType);
services.AddScoped(genericRepositoryType, implRepositoryType);
}
}