You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SqlServerMigrationsSqlGenerator中使用自定义注解添加行级安全策略?

解决方案

问题核心是实体上的自定义注解不会自动同步到CreateTableOperation中,需要通过自定义迁移模型差异处理器,将实体注解传递到迁移操作里,之后就能在SqlGenerator中正常读取。

步骤1:自定义IMigrationsModelDiffer,传递实体注解

创建继承自SqlServerMigrationsModelDiffer的类,重写CreateTable方法,将实体的IsMultiTenant注解复制到生成的CreateTableOperation中:

public class MyMigrationsModelDiffer : SqlServerMigrationsModelDiffer
{
    public MyMigrationsModelDiffer(
        IRelationalTypeMappingSource typeMappingSource,
        IMigrationsAnnotationProvider migrationsAnnotations,
        IChangeDetector changeDetector,
        IUpdateAdapterFactory updateAdapterFactory,
        CommandBatchPreparerDependencies commandBatchPreparerDependencies)
        : base(typeMappingSource, migrationsAnnotations, changeDetector, updateAdapterFactory, commandBatchPreparerDependencies)
    {
    }

    protected override CreateTableOperation CreateTable(
        IEntityType entityType,
        IModel? sourceModel,
        IModel? targetModel,
        DiffContext diffContext)
    {
        var createTableOp = base.CreateTable(entityType, sourceModel, targetModel, diffContext);

        // 读取实体的IsMultiTenant注解并添加到操作对象中
        if (entityType.FindAnnotation("IsMultiTenant") is { Value: bool isMultiTenant } && isMultiTenant)
        {
            createTableOp.AddAnnotation("IsMultiTenant", true);
        }

        return createTableOp;
    }
}

步骤2:注册自定义服务

在DbContext的服务配置中,替换默认的IMigrationsModelDiffer和IMigrationsSqlGenerator:

builder.Services.AddDbContext<YourDbContext>(options =>
    options.UseSqlServer("你的连接字符串")
           .ReplaceService<IMigrationsModelDiffer, MyMigrationsModelDiffer>()
           .ReplaceService<IMigrationsSqlGenerator, MySqlServerMigrationSqlGenerator>());

步骤3:优化SqlGenerator中的注解读取逻辑

可以将原有的判断逻辑优化为更稳健的写法:

protected override void Generate(CreateTableOperation operation, IModel? model, MigrationCommandListBuilder builder, bool terminate = true)
{
    ArgumentNullException.ThrowIfNull(operation);
    ArgumentNullException.ThrowIfNull(builder);

    base.Generate(operation, model, builder, terminate);

    // 读取操作中的IsMultiTenant注解
    if (operation.Annotations.TryGetValue("IsMultiTenant", out var annotation) && annotation.Value is true)
    {
        var tableName = Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema);
        
        builder.AppendLine("ALTER SECURITY POLICY rls.tenantAccessPolicy");
        using (builder.Indent())
        {
            builder
                .AppendLine($"ADD FILTER PREDICATE rls.fn_tenantAccessPredicate(TenantID) ON {tableName},")
                .Append($"ADD BLOCK PREDICATE rls.fn_tenantAccessPredicate(TenantID) ON {tableName}")
                .AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
        }
        EndStatement(builder);
    }
}

补充说明

如果需要给已存在的表添加行级安全策略,还需要在MyMigrationsModelDiffer中重写AlterTable方法,判断实体注解的变化,生成对应的AlterTable操作并传递注解,之后在SqlGenerator中处理AlterTableOperation的逻辑。

内容的提问来源于stack exchange,提问作者Adam Stapleton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:24:56