【问题标题】:How to use EF Core with Azure SQL Shards for .NET 5+?如何将 EF Core 与用于 .NET 5+ 的 Azure SQL Shards 结合使用?
【发布时间】:2022-08-09 21:07:05
【问题描述】:

我们有一个带有客户租户的 SaaS 产品,我们正在尝试实现可扩展的数据库访问,但看起来 ElasticScale github 项目已被放弃。有新的机制吗?如何在现代版本的 EF 中实现可扩展、可管理的数据库分片?

  • 我有同样的问题/问题。你能找到答案/解决方案/建议吗?

标签: c# entity-framework entity-framework-core azure-sql-database azure-elastic-sharding


【解决方案1】:

Microsoft.Azure.SqlDatabase.ElasticScale.Client 包是官方客户端库,它允许 ADO.NET 开发人员创建应用程序,以实现和使用 Azure SQL 数据库中称为数据库分片的模式。但它支持.NET Standard 2.0.NET Framework 4.5.0

弹性数据库功能包括弹性数据库客户端库、弹性数据库拆分合并工具、弹性数据库作业、弹性数据库查询和弹性事务.

有关更多详细信息和示例代码,请参阅Elastic Database client library with Entity Framework

【讨论】:

  • 这没有回答所提出的问题。
  • 这个答案与问题有什么关系?问题显然是针对 EF Core (.NET Core/5+)。
【解决方案2】:

是的,使用拦截器与 EF Core 一起工作是可能的并且效果很好:
https://docs.microsoft.com/en-us/ef/core/logging-events-diagnostics/interceptors

using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Data.Common;

namespace <blah>;

public class RowLevelSecuritySqlInterceptor : DbCommandInterceptor, IRowLevelSecuritySqlInterceptor
{
    public Guid? TenantId { get; set; }

    public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)
    {
        SetSessionContext(command);

        return base.ReaderExecuting(command, eventData, result);
    }

    public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result,
        CancellationToken cancellationToken = new ())
    {
        SetSessionContext(command);

        return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
    }

    public override InterceptionResult<int> NonQueryExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<int> result)
    {
        SetSessionContext(command);

        return base.NonQueryExecuting(command, eventData, result);
    }

    public override ValueTask<InterceptionResult<int>> NonQueryExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = new ())
    {
        SetSessionContext(command);

        return base.NonQueryExecutingAsync(command, eventData, result, cancellationToken);
    }

    public override InterceptionResult<object> ScalarExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<object> result)
    {
        SetSessionContext(command);

        return base.ScalarExecuting(command, eventData, result);
    }
    public override ValueTask<InterceptionResult<object>> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<object> result,
        CancellationToken cancellationToken = new ())
    {
        SetSessionContext(command);

        return base.ScalarExecutingAsync(command, eventData, result, cancellationToken);
    }

    private void SetSessionContext(DbCommand command)
    {
        var tenantId = TenantId is null ? "null" : $"'{TenantId.Value}'";
        command.CommandText = $"EXEC sp_set_session_context @key=N'TenantId', @value={tenantId};" + command.CommandText;
    }
}

您可以为 DI 创建一个接口:

using Microsoft.EntityFrameworkCore.Diagnostics;

namespace <blah>;

public interface IRowLevelSecuritySqlInterceptor : IDbCommandInterceptor
{
    Guid? TenantId { get; set; }
}

并将其注入 DI 容器:

services.TryAddTransient<IRowLevelSecuritySqlInterceptor, RowLevelSecuritySqlInterceptor>();

您的 DbContext 可能类似于:

public partial class MyDbContext
{
    private readonly IRowLevelSecuritySqlInterceptor _rowLevelSecuritySqlInterceptor;
    ...

    public AccountServiceDbContext(
        ...,
        IRowLevelSecuritySqlInterceptor rowLevelSecuritySqlInterceptor) : base(options)
    {
        ...,
        _rowLevelSecuritySqlInterceptor = rowLevelSecuritySqlInterceptor;
    }

    ...

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseSqlServer(...)
            .AddInterceptors(_rowLevelSecuritySqlInterceptor, ... and other interceptors);
    }
}

【讨论】:

    猜你喜欢
    • 2020-07-14
    • 1970-01-01
    • 2019-03-28
    • 2018-11-08
    • 2021-04-19
    • 2020-07-22
    • 2021-09-15
    • 1970-01-01
    • 2021-11-24
    相关资源
    最近更新 更多