【问题标题】:Create Dbcontext at run-time在运行时创建 Dbcontext
【发布时间】:2020-05-13 18:29:58
【问题描述】:

我需要在运行时切换到不同的数据源。有时用户想要连接到不同的数据库服务器来操作数据。可以有超过 100 个具有相同数据库的客户端服务器。原始项目是一个 .net 核心 Web API,服务器名称是一个输入参数。

这就是我的想法。有没有更好的选择?

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    {
    }

    public DbSet<Person> Persons { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>().HasKey(a => a.Id);

    }
}
class Program : IDesignTimeDbContextFactory<MyDbContext>
    {
        static async Task Main(string[] args)
        {
            var _context = new Program().CreateDbContext();
            //transactions
            while (true)
            {
                var server_name = Console.ReadLine();
                if (server_name == "exit")
                    break;
                string[] remoteServer = { server_name };

                //new context
                using var dbContextRemote = new Program().CreateDbContext(remoteServer);

                try
                {
                    dbContextRemote.Database.BeginTransaction();

                    var result = await dbContextRemote.Persons.FindAsync(1);
                    //.....
                    //can be set of queries
                    Console.WriteLine(result?.Name);

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    dbContextRemote.Database.CommitTransaction();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    //dbContextRemote.Database.RollbackTransaction();
                    break;
                }
                _context.Database.CloseConnection();
            }

        }
        public MyDbContext CreateDbContext(string[] args = null)
        {
            if (args == null || args.Length == 0)
                args = new string[] { "localhost" };

            var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
            optionsBuilder.UseSqlServer($"Server={args[0]};Database=SampleDb;Trusted_Connection=True");
            return new MyDbContext(optionsBuilder.Options);
        }
    }

【问题讨论】:

  • 这种方法有什么问题?我可以轻松地为每个数据库查询创建一个包装器并每次都使用它。

标签: c# entity-framework asp.net-core entity-framework-core ef-core-3.0


【解决方案1】:

如果您使用AddDbContext 调用注册您的数据库,您可以利用它的重载,让您可以访问IServiceProvider

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddEntityFrameworkSqlServer()
        .AddDbContext<MyContext>((serviceProvider, options) =>
        {
             var connectionString = serviceProvider.GetService // get your service 
             // which can determine needed connection string based on your logic
             .GetConnectionString();
              options.UseSqlServer(connectionString);
         });
       }
}

同样here 也可以使用 Autofac 实现类似的功能。

【讨论】:

  • 好的。我认为这样我需要事先注册/配置所有数据库。但就我而言,每周都会有一个新数据库。并且有一个单独的 API 调用来检索所有数据库服务器名称(从本地数据库)。提供给每个 API 调用的用户可以从不同的数据库中检索数据。预先注册数据库有什么好处?有什么性能优势吗?真的有必要每次都注射吗
  • 不,您不需要事先注册。您使用不同的连接字符串重用相同的 dbcontext 类(因为所有数据库的结构相同)。您需要为连接字符串实现提供程序,它可以根据当前范围内的信息提供一个(在我的用例中,我从 httpcontext 获取信息),仅此而已。
  • @Lakmal 好处是您可以重用您的 DI 并尽可能以本地方式使用它。
猜你喜欢
  • 2012-09-04
  • 2015-12-28
  • 2021-06-21
  • 1970-01-01
  • 2018-09-13
  • 2012-01-29
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多