Ef Core 全局查询过滤器动态启用禁用
Ef Core Global Query Filter Enable Disable Dynamically
我正在尝试实现一个启用禁用条件的 ef 核心全局查询过滤器。根据我的情况,我有一个名为“FilterStatus”的标志,它的值会随着每个用户而变化。因此任何登录到系统的用户 FilterStatus 值都会更改。我想实现一个全局查询过滤器来根据 FilterStatus 标志过滤数据。
我想出了以下但不起作用的全局查询过滤器的 if-else 语句:
public partial class TableDbContext : DbContext, IDbContext
{
protected Guid TenantId { get; set; }
protected UserClaimFilter UserClaimFilter { get; set; } = new UserClaimFilter();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var tenant = _httpContextAccessor?.HttpContext?.GetTenant();
if (tenant != null)
{
TenantId = Guid.Parse(tenant.Id);
var userClaims =
_httpContextAccessor.HttpContext.Session.GetObject<UserClaimFilter>
(DefaultConstants
.SessionUserClaimStore);
if (userClaims != null)
{
UserClaimFilter = userClaims;
}
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Region>(entity =>
{
if (UserClaimFilter.FilterStatus && UserClaimFilter.RegionClaims.Any())
{
entity.HasQueryFilter(a => a.TenantId == TenantId &&
UserClaimFilter.RegionClaims.Contains(a.RegionCode));
}
else
{
entity.HasQueryFilter(a => a.TenantId == TenantId);
}
});
}
}
在上面的代码中总是 运行 else 部分,即使 UserClaimFilter.FilterStatus 为真。我想是因为第一次 运行 的 OnModelCreating 默认值 UserClaimFilter.FilterStatus 是假的。
有没有根据配置值启用-禁用全局查询过滤器的解决方案?
全局查询过滤条件的所有动态部分必须 (1) 来自 DbContext
成员(与您的代码一样)并且 (2) 是表达式的一部分,而不是在构建表达式时计算一次. EF Core 具有在翻译查询时消除条件表达式的常量 true 或 false 部分的机制,因此您只需将它们包含在表达式中即可。例如
entity.HasQueryFilter(a => a.TenantId == TenantId &&
(!UserClaimFilter.FilterStatus ||
!UserClaimFilter.RegionClaims.Any() ||
UserClaimFilter.RegionClaims.Contains(a.RegionCode))
);
将过滤器应用于查询时,如果 !UserClaimFilter.FilterStatus
或 !UserClaimFilter.RegionClaims.Any()
为真 当时 ,则整个表达式 (a || b || c)
将被视为 constant true 并从生成的查询中删除(因为 (x && true) == x
)。
更新: 如评论中所述,目前 EF Core 并未完全消除整个表达式。 a || b
替换为具有 true
或 false
值的 bool
参数。但是当 bool
参数值为 true
.
时,至少 c
(这是实际的过滤器,在您的情况下为 UserClaimFilter.RegionClaims.Contains(a.RegionCode)
)被消除
我正在尝试实现一个启用禁用条件的 ef 核心全局查询过滤器。根据我的情况,我有一个名为“FilterStatus”的标志,它的值会随着每个用户而变化。因此任何登录到系统的用户 FilterStatus 值都会更改。我想实现一个全局查询过滤器来根据 FilterStatus 标志过滤数据。
我想出了以下但不起作用的全局查询过滤器的 if-else 语句:
public partial class TableDbContext : DbContext, IDbContext
{
protected Guid TenantId { get; set; }
protected UserClaimFilter UserClaimFilter { get; set; } = new UserClaimFilter();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var tenant = _httpContextAccessor?.HttpContext?.GetTenant();
if (tenant != null)
{
TenantId = Guid.Parse(tenant.Id);
var userClaims =
_httpContextAccessor.HttpContext.Session.GetObject<UserClaimFilter>
(DefaultConstants
.SessionUserClaimStore);
if (userClaims != null)
{
UserClaimFilter = userClaims;
}
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Region>(entity =>
{
if (UserClaimFilter.FilterStatus && UserClaimFilter.RegionClaims.Any())
{
entity.HasQueryFilter(a => a.TenantId == TenantId &&
UserClaimFilter.RegionClaims.Contains(a.RegionCode));
}
else
{
entity.HasQueryFilter(a => a.TenantId == TenantId);
}
});
}
}
在上面的代码中总是 运行 else 部分,即使 UserClaimFilter.FilterStatus 为真。我想是因为第一次 运行 的 OnModelCreating 默认值 UserClaimFilter.FilterStatus 是假的。
有没有根据配置值启用-禁用全局查询过滤器的解决方案?
全局查询过滤条件的所有动态部分必须 (1) 来自 DbContext
成员(与您的代码一样)并且 (2) 是表达式的一部分,而不是在构建表达式时计算一次. EF Core 具有在翻译查询时消除条件表达式的常量 true 或 false 部分的机制,因此您只需将它们包含在表达式中即可。例如
entity.HasQueryFilter(a => a.TenantId == TenantId &&
(!UserClaimFilter.FilterStatus ||
!UserClaimFilter.RegionClaims.Any() ||
UserClaimFilter.RegionClaims.Contains(a.RegionCode))
);
将过滤器应用于查询时,如果 !UserClaimFilter.FilterStatus
或 !UserClaimFilter.RegionClaims.Any()
为真 当时 ,则整个表达式 (a || b || c)
将被视为 constant true 并从生成的查询中删除(因为 (x && true) == x
)。
更新: 如评论中所述,目前 EF Core 并未完全消除整个表达式。 a || b
替换为具有 true
或 false
值的 bool
参数。但是当 bool
参数值为 true
.
c
(这是实际的过滤器,在您的情况下为 UserClaimFilter.RegionClaims.Contains(a.RegionCode)
)被消除