ef核心-使用全局过滤器的多租户

时间:2019-05-03 15:48:48

标签: multi-tenant ef-core-2.0 global-filter

每个数据库上下文一次调用

OnModelCreating。这是一个问题,因为每个请求都设置了租户ID。

每次创建dbcontext的新实例时,如何重新配置​​全局过滤器?

如果我不能使用全局过滤器,另一种方法是什么?

更新:

我需要提供一个带有e => e.TenantId == _tenantId之类表达式的通用过滤器。我正在使用以下表达式:

var p = Expression.Parameter(type, "e");
Expression.Lambda(
    Expression.Equal(
        Expression.Property(p, tenantIdProperty.PropertyInfo),
        Expression.Constant(_tenantId))
    p);

由于该命令运行一次,因此_tenantId是固定的。因此,即使更新它,第一个值也会在linq表达式中捕获。

所以我的问题是,设置平等权利的正确方法是什么。

3 个答案:

答案 0 :(得分:0)

此问题已通过以下正确的表达方式予以解决

Expression.MakeMemberAccess(
    Expression.Constant(this, baseDbContextType),
    baseDbContextType.GetProperty("TenantId")

我为所有数据库上下文使用基类。 GetProperty()按原样工作是因为TenantId是公共财产。

答案 1 :(得分:0)

使用EF.Core,您实际上可以使用以下过滤器和语法

protected void OnModelCreating(ModelBuilder modelBuilder)
{
    var entityConfiguration = modelBuilder.Entity<MyTenantAwareEntity>();
    entityConfiguration.ToTable("my_table")
               .HasQueryFilter(e => EF.Property<string>(e, "TenantId") == _tenantProvider.GetTenant())
    [...]

_tenantProvider 是负责从HttpRequest中获取租户的类,可以使用HttpContextAccessor来实现。

答案 2 :(得分:0)

和.. 如果将其与软删除配合使用,则解决方法是: -对于ef core 3.1

internal static void AddQueryFilter<T>(this EntityTypeBuilder 
entityTypeBuilder, Expression<Func<T, bool>> expression)
{
var parameterType = Expression.Parameter(entityTypeBuilder.Metadata.ClrType);
var expressionFilter = ReplacingExpressionVisitor.Replace(
    expression.Parameters.Single(), parameterType, expression.Body);

var currentQueryFilter = entityTypeBuilder.Metadata.GetQueryFilter();
if (currentQueryFilter != null)
{
    var currentExpressionFilter = ReplacingExpressionVisitor.Replace(
        currentQueryFilter.Parameters.Single(), parameterType, currentQueryFilter.Body);
    expressionFilter = Expression.AndAlso(currentExpressionFilter, expressionFilter);
}

var lambdaExpression = Expression.Lambda(expressionFilter, parameterType);
entityTypeBuilder.HasQueryFilter(lambdaExpression);
}

用法:

if (typeof(ITrackSoftDelete).IsAssignableFrom(entityType.ClrType))
modelBuilder.Entity(entityType.ClrType).AddQueryFilter<ITrackSoftDelete>(e => IsSoftDeleteFilterEnabled == false || e.IsDeleted == false);
if (typeof(ITrackTenant).IsAssignableFrom(entityType.ClrType))
modelBuilder.Entity(entityType.ClrType).AddQueryFilter<ITrackTenant>(e => e.TenantId == MyTenantId);

感谢YZahringer