c# - 为不同的 Web 项目在 DI 中更改注册的 DbContext,但维护使用它的通用库
问题描述
我遇到了这个Magic super DRY 代码,并决定自己做一个简单的代码。我基本上计划创建通用库,当我在新项目中应用它时,我将只注入项目特定的 DbContext 并拥有一个简单的 CRUD 端点,所需的代码更少。
话虽如此,我已经创建了通用库并且能够成功地对其进行测试。现在我试图在一个新项目中使用它,我找不到将我的项目特定的 DbContext 注入库的方法。
这是我到目前为止所得到的:
通用库:
数据库上下文
public class ApiContext : DbContext
{
//Sample DbSet during my testing in same solution
public DbSet<RootAccount> RootAccounts { get; set; }
public ApiContext(DbContextOptions<ApiContext> options) : base(options){}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RootAccount>().ApplyBaseModelSchema();
modelBuilder.Entity<RootAccount>().Property(m => m.Name).IsRequired();
}
}
通用存储库
public class GenericRepository<TEntity> where TEntity : BaseModel
{
public ApiContext Context { get; }
internal DbSet<TEntity> DbSet;
public GenericRepository(ApiContext context)
{
this.Context = context;
this.DbSet = context.Set<TEntity>();
Context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}
public virtual async Task<TEntity> GetByIDAsync(object id)
{
return await DbSet.FindAsync(id);
}
public virtual void Insert(TEntity entity)
{
//Added another layer of repository mainly for purposes such as this
entity.CreatedDate = DateTime.UtcNow;
DbSet.Add(entity);
}
//more methods here
}
工作单元
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly Dictionary<Type, object> repositories = new Dictionary<Type, object>();
private ApiContext _context;
public UnitOfWork(ApiContext webApiContext)
{
_context = webApiContext;
}
public GenericRepository<TEntity> GetRepository<TEntity>() where TEntity : BaseModel
{
if (repositories.Keys.Contains(typeof(TEntity)))
return repositories[typeof(TEntity)] as GenericRepository<TEntity>;
var repository = new GenericRepository<TEntity>(_context);
repositories.Add(typeof(TEntity), repository);
return repository;
}
public ApiContext Context { get => _context; }
public async Task<int> SaveAsync()
{
try
{
await _context.SaveChangesAsync();
}
catch (Exception e)
{
//System.IO.File.AppendAllText(@"E:\errors.txt", e.Message);
throw e;
}
return 0;
}
}
CrudService
public class CrudService<T> : ICrudService<T> where T : BaseModel, new()
{
private IUnitOfWork _unitOfWork;
private IDataMapper _mapper;
public CrudService(IUnitOfWork unitOfWork, IDataMapper mapper)
{
_unitOfWork = unitOfWork;
_mapper = mapper;
}
public async Task<DTO> GetAsync<DTO>(int id) where DTO : BaseDtoModel, new()
{
var model = await _unitOfWork.GetRepository<T>().GetByIDAsync(id);
var dto = _mapper.Map<DTO>(model);
return dto;
}
public async Task<int> AddAsync<DTO>(DTO dtoModel) where DTO : BaseDtoModel, new()
{
var model = _mapper.Map<T>(dtoModel);
_unitOfWork.GetRepository<T>().Insert(model);
await _unitOfWork.SaveAsync();
return model.Id;
}
//more methods here
}
启动
public void ConfigureServices(IServiceCollection services)
{
//this works because the UoW and GenericRepository hardcodes ApiContext and the same type is registered here.
services.AddDbContext<ApiContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("AppConnString")));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddTransient<IDataMapper, DataMapper>();
services.AddTransient(typeof(ICrudService<>), typeof(CrudService<>));
}
问题
如果我将这个库用于一个新项目,比如说一个会计系统,我想AccountingDbContext
在 Startup 中注册一个,而不是ApiContext
显然。我试图重构我的 UoW 和 GenericRepository 以使用基类DbContext
,但似乎也不起作用。我的直觉告诉我要创建一个IDbContext
,但我不知道如何实现它。
对不起,代码墙,但我相信他们会比我在我的文章中更好地解释我的问题。先感谢您!
解决方案
好吧,在为此苦苦挣扎了几个小时之后,我在发布此问题几分钟后找到了解决方案。
它让我觉得我仍然可以重构我的UoW
并GenericRepository
使用通用的DbContext
. 然后在启动时,我可以像这样提供一个不同的实现DbContext
:
services.AddDbContext<DbContext, ApiContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("AppConnString")));
我不知道我们可以做到这一点,并且我们只能在注册接口时提供一个实现(因此我的想法IDbContext
)。现在测试它,到目前为止一切似乎都很好。
推荐阅读
- reactjs - Express 或 react 正在删除标题
- jquery - 在 Google Chat 中创建新话题 - 如何发送新的指定话题密钥?
- javascript - 我如何在reactjs中更新获取请求
- json - 如何在golang中打印json值
- ios - iOS 订阅 DID_CHANGE_RENEWAL_STATUS 通知:latest_expired_receipt vs latest_receipt
- android - TouchOpacity 组件设置为在 android 中定位绝对不可点击
- java - 尝试使用 gzip 编码但得到 400 响应的 HTTPUrlConnection 编写 post 语句
- java - 根据另一个字符串数组的值,仅从数组中提取某些对象
- javascript - 使用 jqTree 在节点删除时触发事件
- javascript - 如何使用 javascript 触发器管理 PHP 列表