Home > Software engineering >  Ef Core Global Query Filter Enable Disable Dynamically
Ef Core Global Query Filter Enable Disable Dynamically

Time:02-18

I'm trying to implement an ef core global query filter with enable disable conditions. According to my scenario, I have a flag called 'FilterStatus' and its value changes to every user. So any user logged in to the system FilterStatus value is changed. I want to implement a global query filter to filter data according to the FilterStatus flag.

I've come up with the following but does not work if-else statement of global query filter:

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);
                }

            });
   }
}

In the above code always run the else part even if the UserClaimFilter.FilterStatus is true. I think because of the first time running the OnModelCreating default value of UserClaimFilter.FilterStatus is false.

Any solution to enable-disable global query filter according to the configuration value?

CodePudding user response:

All the dynamic parts of the global query filter conditions must (1) originate from DbContext members (as with your code) and (2) be part of the expression rather than evaluated once when building the expression. EF Core has mechanism for eliminating the constant true or false parts of conditional expressions when translating the query, so all you need is to include them in the expression. e.g.

entity.HasQueryFilter(a => a.TenantId == TenantId &&
    (!UserClaimFilter.FilterStatus ||
     !UserClaimFilter.RegionClaims.Any() || 
     UserClaimFilter.RegionClaims.Contains(a.RegionCode))
);

When applying the filter to a query, if !UserClaimFilter.FilterStatus or !UserClaimFilter.RegionClaims.Any() is true at that time, then the whole expression (a || b || c) will be considered constant true and eliminated from the generated query (because (x && true) == x).

Update: As mentioned in the comments, currently EF Core does not fully eliminate the whole expression. a || b are replaced with bool parameter having either true or false value. But at least c (which is the actual filter, UserClaimFilter.RegionClaims.Contains(a.RegionCode) in your case) is eliminated when the bool parameter value is true.

  • Related