gpt4 book ai didi

.net - 使用 Entity Framework Core 的分片策略

转载 作者:行者123 更新时间:2023-12-05 01:24:16 25 4
gpt4 key购买 nike

我正在使用 Asp.Net Core 和 Entity Framework Core 开发一个新的 REST API。我们将从使用水平数据库分区(分片)的遗留系统移植数据。我试图想出一种在 EF Core 中处理这个问题的好方法。我们之前的分片策略涉及一个中央 Prime 数据库和多个客户数据库。所有查询均包含 CustomerId .我们使用 CustomerId 查询 Prime 数据库,以确定哪个 Customer 数据库包含特定客户的数据。数据库模式如下所示:

Prime 数据库

 dbo.Database  
DatabaseId INTEGER
ConnectionString VARCHAR(200)

dbo.Customer
CustomerId BIGINT
DatabaseId INTEGER

客户数据库
dbo.Order  
CustomerId BIGINT
OrderId INT
...

获取订单的示例 REST 调用类似于 http://foo.com/api/Customers/{CustomerId}/Orders/{OrderId}
我需要我的 CustomerDbContext对每个 REST 请求使用动态确定的连接字符串。我应该创建 DbContext 的新实例吗?每个请求?或者,我可以在运行时更改连接字符串吗?

如果我正在创建新的 DbContexts,我应该怎么做?我能找到的大多数示例代码都使用 Startup.cs 中的依赖注入(inject)来创建单例 DbContext .

最佳答案

这就是我想出的。它仍然非常粗糙,我非常感谢可能提供的任何批评。

我在 dbo.Database 中添加了“UseForNewCustomer BOOLEAN”。我正在使用数据库迁移来动态创建新的分片。

ShardDbContextFactory

public class ShardDbContextFactory : IDbContextFactory<ShardDbContext>
{
public ShardDbContext Create(DbContextFactoryOptions opts)
{
return this.Create("This-Connection-String-Isn't-Used");
}

public ShardDbContext Create(string connectionString)
{
var optsBldr = new DbContextOptionsBuilder<ShardDbContext>();
//This is for PostGres. If using MS Sql Server, use 'UseSqlServer()'
optsBldr.UseNpgsql(connectionString);
return new ShardDbContext(optsBldr.Options);
}
}

ShardContextService.cs
public interface IShardContextService {
ShardDbContext GetContextForCustomer(int customerId);
void ActivateShard(string connectionString, string dbType);
}

public class ShardContextService : IShardContextService {
private readonly PrimeDbContext _primeContext;
public ShardContextService(SystemDbContext primeContext) {
_primeContext = primeContext;
}

public CustomerDbContext GetContextForCustomer(int customerId)
{
Database shard = null;
var customer = _primeContext.Customers
.Include(m=>m.Database)
.SingleOrDefault(c=>c.CustomerId == customerId);
if (customer == null)
{
shard = _primeContext.Databases.Single(db=>db.UseForNewCustomer);

if (shard == null) throw new System.Exception("Unable to determine shard: This is a new customer, and no shards are designated as useable for new customers.");

_primeContext.Customers.Add(new Customer {
CustomerId = customerId,
DatabaseId = shard.DatabaseId
});

_primeContext.SaveChanges();
}
else
{
shard = customer.Database;
}
return (new ShardDbContextFactory()).Create(shard.ConnectionString)
}

public void ActivateShard(string connectionString)
{
using (var customerContext = (new ShardDbContextFactory()).Create(connectionString))
{
customerContext.Database.Migrate();
}

var previous = _primeContext.Databases.SingleOrDefault(d=>d.UseForNewCustomers);
if (previous != null)
{
previous.UseForNewCustomers = false;
}

var existing = _primeContext.Databases.SingleOrDefault(d=>d.ConnectionString == connectionString);
if (existing != null)
{
existing.UseForNewCustomers = true;
}
else
{
_primeContext.Databases.Add(new Database {
ConnectionString = connectionString,
UseForNewCustomers = true
});
}
_primeContext.SaveChanges();
}
}

用于创建新分片的 Controller 操作
[HttpPost]
public IActionResult Shard([FromBody] string connectionString) {
try {
_shardContextService.ActivateShard(connectionString);
return Ok("Shard activated");
} catch (System.Exception e) {
return StatusCode(500, e);
}
}

用于查询的 Controller 操作
[HttpGet]
[Route("/api/Customers/{customerId}/Orders/{orderId}")]
public virtual IActionResult GetOrdersForCustomer([FromRoute]long customerId, [FromRoute] long orderId)
{
using (var ctx = _shardContextService.GetContextForCustomer(customerId))
{
var order = ctx.Orders.Where(o => o.CustomerId == customerId && o.OrderId = orderId).Single();
if (order == null) return NotFound("Unable to find this order.");
else return new ObjectResult(order);
}
}

关于.net - 使用 Entity Framework Core 的分片策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39298630/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com