【问题标题】:Entity Framework Multiple Connections Error实体框架多连接错误
【发布时间】:2019-09-20 21:18:51
【问题描述】:

我有一个场景,其中我在 appsettings.json 下定义了多个连接字符串,如下所示:

"ConnectionString": {
    "ConnectionZone1": "Server=(localdb)\\mssqllocaldb;Database=Blogging;Trusted_Connection=True;",
    "ConnectionZone2": "Server=localhost;Database=Blogging;Trusted_Connection=True;"
},

我也在我的 startup.cs 文件中注册了这个:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DbContextZone1>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("ConnectionZone1")));

        services.AddDbContext<DbContextZone2>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("ConnectionZone2")));

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

我使用数据库优先方法创建了模型和上下文类,并按如下方式注册了我的上下文类:

public partial class BloggingContext : DbContext
{
    public BloggingContext()
    {
    }

    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    {
    }

    public virtual DbSet<Blog> Blog { get; set; }
    public virtual DbSet<Post> Post { get; set; }

并创建了另外两个继承自上述主基类的上下文类:

public class DbContextZone1 : BloggingContext
{
    public DbContextZone1()
    {
    }        
}

public class DbContextZone2 : BloggingContext
{
    public DbContextZone2()
    {

    }
}

现在我已经创建了我的 API 控制器并尝试调用这些上下文方法。

[HttpGet]
    public async Task<ActionResult<IEnumerable<object>>> GetItems()
    {
        if (alternate)
        {
            alternate = false;
            using (var context = new DbContextZone1())
            {
                return await context.Blog.ToListAsync();
            }
        }

        using(var context = new DbContextZone2())
        {
            return await context.Post.ToListAsync();
        }            
    }

问题是当我运行我的应用程序时,它会抛出错误,我的上下文类应该具有参数化构造函数以便传递选项。

那么在 DbContextZone1 和 DbContextZone2 构造函数中会出现哪个上下文选项参数?我试过这样放,但是当我调用 API 控制器时它永远不会工作并抛出错误:

public class DbContextZone1 : BloggingContext
{
    public DbContextZone1(DbContextOptions<BloggingContext> options)
        : base(options)
    {
    }        
}

public class DbContextZone2 : BloggingContext
{
    public DbContextZone2(DbContextOptions<BloggingContext> options)
        : base(options)
    {

    }
}

这是错误:

那么关于如何实现多个连接或使我的代码正确的任何帮助或代码想法或建议?

【问题讨论】:

    标签: asp.net-core-webapi ef-core-2.2


    【解决方案1】:

    从您的 appsettings.json 中,您似乎想连接到不同服务器中的同一个数据库。您无需创建基本 DbContext,只需继承默认 DbContext,如下所示:

    public class DbContextZone1 : DbContext
    {
        public DbContextZone1(DbContextOptions<DbContextZone1> options)
            : base(options)
        {
        }
        public virtual DbSet<Blog> Blog { get; set; }
    }
    public class DbContextZone2 :DbContext
    {
        public DbContextZone2(DbContextOptions<DbContextZone2> options)
            : base(options)
        {
        }
        public virtual DbSet<Post> Post { get; set; }
    }
    

    然后像下面这样调用 API 控制器:

    private readonly DbContextZone1 _context1;
    private readonly DbContextZone2 _context2;
        public ABCController(DbContextZone1 context1, DbContextZone2 context2)
        {
            _context1 = context1;
            _context2 = context2;
        }
        [HttpGet]
        public async Task<ActionResult<IEnumerable<object>>> GetItems()
        {
            //....
            if (alternate)
            {
                alternate = false;
                return await _context1.Blog.ToListAsync();
            }
            return await _context2.Post.ToListAsync();
        }
    

    【讨论】:

    • 是的,我恢复了这种方法并且这有效,但是如果您继续为不同的数据库服务器添加上下文怎么办。我有接近 8 个不同的连接字符串,这将导致使用关系创建 8 个不同的上下文方法。
    • 您的想法非常好。据我所知,在 EF Core 中,如果您有多个连接字符串,则需要创建对应的上下文,然后您可以在控制器中调用它。也许您可以发布一个关于连接到多个连接字符串的更好做法的新线程。
    【解决方案2】:

    将您的 DbContext Cunstructors 更改为:

    public class DbContextZone1 : BloggingContext
    {
        public DbContextZone1(DbContextOptions<DbContextZone1> options)
            : base(options)
        {
        }        
    }
    
    public class DbContextZone2 : BloggingContext
    {
        public DbContextZone2(DbContextOptions<DbContextZone2> options)
            : base(options)
        {
    
        }
    }
    

    更新:

    如果您在更改 DbContext 类后遇到错误,是因为您尝试访问如下默认构造函数:

    using (var context = new DbContextZone1())
    

    当你的类中没有实现默认构造函数时。由于您已经在 .net core DI 系统中注册了 DbContext 类,您只需在 Controller 的构造函数中注入 DbContextZone1 和 DbContextZone2 即可轻松访问上下文。但在此之前,您应该将 DbSet 添加到 DbContext 类并将它们更改为:

    public class DbContextZone1 : BloggingContext
    {
        public DbContextZone1(DbContextOptions<DbContextZone1> options)
            : base(options)
        { }
    
        public virtual DbSet<Blog> Blogs { get; set;}
    }
    
    public class DbContextZone2 : BloggingContext
    {
        public DbContextZone2(DbContextOptions<DbContextZone2> options)
            : base(options)
        { }
    
        public virtual DbSet<Post> Posts { get; set;}
    }
    

    注意:您可以将 DbSet 保存在 BloggingContext 中,然后通过控制器中的_context 访问它们,但像上面那样移动它们会使您的上下文隔离,并将单一职责交给上下文。

    现在你的控制器应该是这样的:

    private readonly DbContextZone1 _context1;
    private readonly DbContextZone2 _context2;
    public MyController(DbContextZone1 context1, DbContextZone2 context2)
    {
        _context1 = context1;
        _context2 = context2;
    }
    
    [HttpGet]
    public async Task<ActionResult<IEnumerable<object>>> GetItems()
    {
        if (alternate)
        {
            alternate = false;
            return await _context1.Blogs.ToListAsync();
        }
        return await _context2.Posts.ToListAsync();
    }
    

    【讨论】:

    • 我已经尝试过了,但它不起作用。获取部分“base(options)”的错误,它无法将 DbContextZone2 和 DbContextZone1 转换为 BloggingContext。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    相关资源
    最近更新 更多