如何在 EF Core 和 C# 中使用数据库分片"

Posted

技术标签:

【中文标题】如何在 EF Core 和 C# 中使用数据库分片"【英文标题】:How to use database sharding with EF Core and C#" 【发布时间】:2020-08-21 06:05:39 【问题描述】:

我目前正在将我使用了 6 年的 C# 应用程序转换为 .NET Core v3 和 EF Core(也使用 Blazor)。 除了分片部分,大部分都在工作。 我们的应用程序为每个客户创建一个新数据库。我们或多或少地使用了这个代码:https://docs.microsoft.com/en-us/azure/sql-database/sql-database-elastic-scale-use-entity-framework-applications-visual-studio 我现在正在尝试将其转换为 EF Core,但在这部分卡住了:

        // C'tor to deploy schema and migrations to a new shard
        protected internal TenantContext(string connectionString)
            : base(SetInitializerForConnection(connectionString))
        
        

        // Only static methods are allowed in calls into base class c'tors
        private static string SetInitializerForConnection(string connnectionString)
        
            // We want existence checks so that the schema can get deployed
            Database.SetInitializer<TenantContext<T>>(new CreateDatabaseIfNotExists<TenantContext<T>>());
            return connnectionString;
        

        // C'tor for data dependent routing. This call will open a validated connection routed to the proper
        // shard by the shard map manager. Note that the base class c'tor call will fail for an open connection
        // if migrations need to be done and SQL credentials are used. This is the reason for the 
        // separation of c'tors into the DDR case (this c'tor) and the internal c'tor for new shards.
        public TenantContext(ShardMap shardMap, T shardingKey, string connectionStr)
            : base(CreateDDRConnection(shardMap, shardingKey, connectionStr), true /* contextOwnsConnection */)
        
        

        // Only static methods are allowed in calls into base class c'tors
        private static DbConnection CreateDDRConnection(ShardMap shardMap, T shardingKey, string connectionStr)
        
            // No initialization
            Database.SetInitializer<TenantContext<T>>(null);

            // Ask shard map to broker a validated connection for the given key
            var conn = shardMap.OpenConnectionForKey<T>(shardingKey, connectionStr, ConnectionOptions.Validate);
            return conn;
        

上述代码无法编译,因为数据库对象在 EF Core 中不存在这种方式。 我假设我可以在某处使用TenantContext.Database.EnsureCreated(); 来简化它。但我不知道如何修改方法,删除哪些,更改哪些(以及如何)。

当然,我一直在寻找使用分片和 EF Core 的示例,但找不到。 这里有没有人以前在 EF Core 中做过这个并且愿意分享?

我正在专门寻找在startup.cs 中添加的内容以及在创建新客户端时如何创建新的分片/数据库。

【问题讨论】:

嘿 Paul,您是在问如何使用 EF Core 自动迁移数据库?还是您在 EF Core 中创建分片连接时遇到特定错误或问题? 嗨,马克,我已经更新了我的帖子。我无法编译 EF 代码,因为 EF Core 中不存在 Database 对象。 小心你想要的。在尝试让 EfCore 工作几个月后,我现在要回到 Ef 经典版——它在 .NET Core 上可用。生成的 SQL 有太多限制,这在 3.1 中变得更糟,这要归功于“哦,我们甚至没有尝试在客户端上进行评估”。 感谢@TomTom 的警告。我同意。我们开始转换为 .NET Core v3 和 EF Core v3,期待 v3 意味着它是否相当成熟。但是,如果你开箱即用,就很难让它发挥作用。我还花了数周时间与 MS Identity 集成,但无法正常工作。我们现在使用谷歌登录。分片也是这样,没有示例代码 @PaulMeems 你解决了这个问题吗?我们仍然有类似的问题。 【参考方案1】:

对于我正在开发的应用程序,在请求时间之前无法发现所需的分片(例如,知道什么用户发出请求,然后将该用户路由到他们的数据库)。这意味着上面提出的OnConfiguring 解决方案不可行。

我通过使用IDbContextFactory&lt;TContext&gt; 解决了这个问题,并在其之上定义了一个扩展,它可以根据您的需要设置连接字符串。我相信数据库连接是在 EF 中延迟创建的,您可以设置连接字符串,直到 EF 首先需要实际连接到数据库。

就我而言,它看起来像这样:

var dbContext = _dbContextFactory.CreateDbContext();
var connectionString = $"DataSource=_sqlliteDirectory/tenant_tenant.TenantId.db";

dbContext.Database.SetConnectionString(connectionString);

缺点是它破坏了数据库抽象(这段代码知道我的数据库是本地 sqllite 实例)。我的应用程序的这一层不需要抽象,但如果需要,它是可以解决的。

【讨论】:

【参考方案2】:

在 EF.Core 中只需解析 OnConfiguring 中的分片。 EG

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

    var con = GetTenantConnection(this.tenantName);

    optionsBuilder.UseSqlServer(con,o => o.UseRelationalNulls());

    base.OnConfiguring(optionsBuilder);

请注意,如果您有一个返回open DbConnections 的服务或工厂,那么您需要在DbContext.Dispose() 中Close()/Dispose() 它们。如果你得到一个连接字符串或一个关闭的连接,那么 DbContext 将负责关闭连接。

ASP.NET Core 最佳实践可能需要在 DbContext 中注入 ITenantConfiguration 服务或类似的东西。但模式是一样的。只需将注入的服务实例保存到 DbContext 字段并在 OnConfiguring 中使用即可。

【讨论】:

感谢@david-browne-microsoft 我也在学习.NET Core,这让我很难理解如何实现所有部分。您是否有完整的示例和/或一些文档链接? 如果GetTenantConnection() 是异步的,你应该怎么做? @david-browne-microsoft。我在这里看不到任何回应。您是否有完整的示例和/或一些文档链接?

以上是关于如何在 EF Core 和 C# 中使用数据库分片"的主要内容,如果未能解决你的问题,请参考以下文章

C# EF Core 模型独立 FK

从查询 C#、EF Core 返回一个值

如何首先将 EF Core 代码与 azure synapse 一起使用

EF Core Seeding 机制不插入数据

C# 数据操作系列 - 5. EF Core 入门

多对多 EF Core 已被跟踪 - C# Discord Bot