通过Entity Framework Core将多个数据库连接到.NET Core项目

3

我正在尝试创建一个.NET Core应用程序,它连接到多个数据库,但只使用一个通用的存储库包含了所有CRUD操作的逻辑。如何最好地实现这一点?

    public Repository(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
        _set = _dbContext.Set<T>();
    }

以下是我的仓库构造函数。在这里,我注入了ApplicationDbContext。我正在寻找一种方法使这个ApplicationDbContext成为泛型,这样我只需要一个仓库,在其中可以注入不同的上下文以访问多个数据库。基本上我正在寻找这样的东西:
public class Repository_1<T> where T:EntityBase
{
    public Repository_1(IDbContext dbContext)
    {

    }
}

我想知道在哪里可以替换dbContext,并用连接到另一个数据库的其他上下文来代替它。


那么在您的情况下,您是否有具有相同模式的不同数据库?还是每个模式都是独特的? - MichaelM
不,每个模式都是独一无二的。 - wserr
所以你基本上想要一个仓库容器来保存所有的上下文? - MichaelM
你的意思是像这样吗:https://ibb.co/2t9sPqH - Iuri Farenzena
4个回答

8
创建基本上下文并将所有设置包含在其中,DBSET:
public abstract class BaseContext : DbContext
{
    public BaseContext(DbContext options)
    : base(options)
    { }
    public DbSet<object> FirstDbSet { get; set; }
    ...
}

继承BaseContext用于两个数据库(DBs):

public class NavaContext : BaseContext
{
    public NavaContext (DbContext<NavaContext> options) : base(options)
    {

    }
}

public class StackContext : BaseContext
{
    public StackContext(DbContext<StackContext> options) : base(options)
    {

    }
}

并在Startup.cs中注册两者:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<NavaContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LATAMConnectionString")));
    services.AddDbContext<StackContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EUConnectionString")));

    // Autofac
    var builder = new ContainerBuilder();

    // needed only if you plan to inject ICollection<BaseContext>
    builder.RegisterType<NavaContext>().As<BaseContext>();
    builder.RegisterType<StackContext>().As<BaseContext>();

    builder.Populate(services);


    return new AutofacServiceProvider(builder.Build());
}

appsettings.json中添加连接字符串:

"ConnectionStrings": {
  "NavaConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "StackConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
}

现在,您可以注入两个上下文:

public class ReportRepository : IReportRepository
{
    private readonly NavaContext latamDbContext;
    private readonly StackContext euDbContext;

    public ReportRepository(NavaContext latamDbContext, StackContext euDbContext)
    {
        this.latamDbContext = latamDbContext;
        this.euDbContext = euDbContext;
    }
}

或者如果您计划注入上下文的集合

public class ReportRepository : IReportRepository
{
    private readonly ICollection<BaseContext> dbContexts;

    public ReportRepository(ICollection<BaseContext> dbContexts)
    {
        this.dbContexts = dbContexts;
    }
}

要访问特定上下文:

var _stackContext= dbContexts.FirstOrDefault(x => x is StackContext) as StackContext;
var _navaContext= dbContexts.FirstOrDefault(x => x is NavaContext) as NavaContext;

我能帮你吗? - Mojtaba Nava
几乎 - 实际上我想每种类型都有一个存储库,例如用户存储库,我需要连接到正确的数据库(其中包含User表)。我不想在我的存储库中拥有上下文集合,只有一个。这可能吗? - wserr
当然可以。选择最优的存储库方法,您可以定义两个数据库。 - Mojtaba Nava
你是什么意思? - wserr

4
您可以为您的存储库设置两个参数,并对它们添加约束,假设您的dbContext是从 DbContext 继承而来。
public class TestRepository<TContext, T> : ITestRepository<TContext,T> 
    where TContext : DbContext
    where T : BaseEntity
{

    private readonly TContext _context;
    private DbSet<T> entities;


    public TestRepository(TContext context)
    {
        _context = context;
        entities = context.Set<T>();
    }



    public List<T> GetAll()
    {

        return entities.AsNoTracking().ToList();
    }
}

ITestReposiroty:

public interface ITestRepository<TContext,T>
    where TContext : DbContext
    where T : BaseEntity
{       
    List<T> GetAll();
}

Startup.cs

services.AddScoped(typeof(ITestRepository<,>), typeof(TestRepository<,>));

控制器:

public class ProductsController : ControllerBase
{
    private readonly ITestRepository<ApplicationDbContext, Product> _repository;

    public TestRepoController(ITestRepository<ApplicationDbContext, Product> repository)
    {
        _repository = repository;
    }
    // GET api/products

    [HttpGet]
    public List<Product> Get()
    {
        return _repository.GetAll();
    }
}

0

BaseRepository类可以像这样使用,并且它在数据访问层类上使用继承。

public class GenericRepository<TEntity, TContext> : IGenericRepository<TEntity> 
    where TEntity : class 
    where TContext : DbContext, new()
    {
        private readonly DbContext _context;
        private readonly DbSet<TEntity> _dbSet;
        public GenericRepository()
        {
            _context = new TContext();
            _dbSet = _context.Set<TEntity>();
        }
    
    }

数据访问类;

public class ProductDal:GenericRepository<Product,AppDbContext>,IProductDal
{
}

如果使用依赖注入数据访问类必须注册。通用存储库无法注册,因为它在类内部实例化。_context = new TContext();


0
在你的 RepositoryBase 类中:
public abstract class RepositoryBase<TContext, TEntity>
   where TContext : DbContext
   where Entity: class 

public TContext Context { get; private set; }

public RepositoryBase(TContext context)
{
    this.Context = context;
}

public IQueryable<TEntity> GetAll()
{
        return this.Context.Set<TEntity>().AsNoTracking();
}

从特定的存储库中使用:

public class ComputerGroupRepo : RepositoryBase<RequestContext, ComputerGroup> 
{
    public ComputerGroupRepo()
       : base(new RequestContext())
    {
    }

    public IQueryable<ComputerGroup> GetComputerGroups()
    {
        IQueryable<ComputerGroup> result = this.GetAll()
            .Include(v => v.ComputerGroupIps);

        return result;
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接