首页 > 解决方案 > 为不同的 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,但我不知道如何实现它。

对不起,代码墙,但我相信他们会比我在我的文章中更好地解释我的问题。先感谢您!

标签: c#entity-frameworkentity-framework-coreasp.net-core-webapidbcontext

解决方案


好吧,在为此苦苦挣扎了几个小时之后,我在发布此问题几分钟后找到了解决方案。

它让我觉得我仍然可以重构我的UoWGenericRepository使用通用的DbContext. 然后在启动时,我可以像这样提供一个不同的实现DbContext

     services.AddDbContext<DbContext, ApiContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("AppConnString")));

我不知道我们可以做到这一点,并且我们只能在注册接口时提供一个实现(因此我的想法IDbContext)。现在测试它,到目前为止一切似乎都很好。


推荐阅读