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

15
我目前正在将我的6年C#应用程序转换为.NET Core v3和EF Core(还使用Blazor)。 它的大部分功能都能正常工作,除了Sharding部分。 我们的应用程序为每个客户端创建一个新的数据库。我们使用的代码大致如下:https://learn.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中不存在Database对象。我认为可以使用TenantContext.Database.EnsureCreated();来简化它。但我不知道如何修改方法,哪些需要删除,哪些需要更改(以及如何更改)。
当然,我一直在搜索使用分片和EF Core的示例,但没有找到。这里有人在EF Core中做过这个并愿意分享吗?
我特别想知道在startup.cs中要放什么,以及在创建新客户端时如何创建新的分片/数据库。

嘿,保罗,你是在问如何使用EF Core自动迁移数据库吗?还是在创建EF Core中的分片连接时遇到了特定的错误或问题? - Code Slinger
嗨,马克,我更新了我的帖子。我无法编译EF代码,因为在EF Core中不存在Database对象。 - Paul Meems
小心你所期望的。经过数月的尝试让EfCore工作,我现在正在回到Ef classic - 它可用于.NET Core。生成的SQL有太多限制,在3.1中变得更糟,因为“哦,我们甚至不尝试在客户端上评估”。 - TomTom
感谢@TomTom的警告。我同意。我们开始转换为.NET Core v3和EF Core v3,期望v3是非常成熟的。但是,如果你想要做一些创新的工作,就很难搞定了。我也花了几周时间集成MS Identity,但没能搞定。我们现在使用Google登录。分片也是类似的情况,没有示例代码。 - Paul Meems
@PaulMeems,你解决了这个问题吗?我们仍然有类似的问题。 - Milan M.
这是我在2016年与同样的问题搏斗: https://dev59.com/TZrga4cB1Zd3GeqPmnDG - Homr Zodyssey
2个回答

7
在EF.Core中,只需在OnConfiguring中解析分片即可。例如:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    var con = GetTenantConnection(this.tenantName);

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

    base.OnConfiguring(optionsBuilder);
}

注意,如果您有一个返回 打开的 DbConnections 的服务或工厂,则需要在 DbContext.Dispose() 中 Close()/Dispose() 它们。如果您获取一个连接字符串或关闭的连接,则 DbContext 将负责关闭连接。
ASP.NET Core 最佳实践可能要求在您的 DbContext 中注入一个 ITenantConfiguration 服务或类似的东西。但模式是相同的。只需将注入的服务实例保存到一个 DbContext 字段中,并在 OnConfiguring 中使用它。

2
谢谢@david-browne-microsoft。我也在学习.NET Core的过程中,这让我很难理解如何实现所有部分。您有完全可用的示例和/或文档链接吗? - Paul Meems
如果 GetTenantConnection() 是异步的,你应该怎么做? - Phil
1
@david-browne-microsoft。我在这里没有看到任何回应。您是否有一个完全可用的示例和/或一些文档链接? - Milan M.

0
在我正在开发的应用程序中,所需的分片直到请求时间才能被发现(例如,知道是哪个用户在发出请求,然后将该用户路由到他们的数据库)。这意味着上面提出的OnConfiguring解决方案不可行。
我通过使用IDbContextFactory<TContext>来解决这个问题,并在其之上定义了一个扩展,根据您想要的任何内容设置连接字符串。我相信EF中的数据库连接是惰性创建的,直到EF首次需要实际连接到数据库为止,您可以设置连接字符串。
在我的情况下,它看起来像这样:
var dbContext = _dbContextFactory.CreateDbContext();
var connectionString = $"DataSource={_sqlliteDirectory}/tenant_{tenant.TenantId}.db";

dbContext.Database.SetConnectionString(connectionString);

缺点是它破坏了数据库抽象层(这段代码知道我的数据库是一个本地的SQLite实例)。在我应用程序的这个层面上,抽象化并不是必需的,但如果需要的话,这是一件非常可以解决的事情。


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