Skip to content

HasQueryFilter does not compile expression correctly in some cases #9502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
hikalkan opened this issue Aug 21, 2017 · 2 comments
Closed

HasQueryFilter does not compile expression correctly in some cases #9502

hikalkan opened this issue Aug 21, 2017 · 2 comments
Assignees

Comments

@hikalkan
Copy link

Hi,

I'm having a strange problem with new global query filters (HasQueryFilter). My code is complicated since I'm developing an application framework. So, I will share the related code.

  1. Using HasQueryFilter like that:
modelBuilder.Entity<TEntity>().HasQueryFilter(CreateFilterExpression<TEntity>());
  1. CreateFilterExpression is defined as below:
protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>() where TEntity : class
{
    Expression<Func<TEntity, bool>> expression = PredicateBuilder.True<TEntity>();

    if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
    {
        expression = expression.And(e => !IsSoftDeleteFilterEnabled || !((ISoftDelete) e).IsDeleted);
    }

    if (typeof(IMayHaveTenant).IsAssignableFrom(typeof(TEntity)))
    {
        expression = expression.And(e => !IsMayHaveTenantFilterEnabled || ((IMayHaveTenant)e).TenantId == CurrentTenantId);
    }

    if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(TEntity)))
    {
        expression = expression.And(e => !IsMustHaveTenantFilterEnabled || (CurrentTenantId == null || ((IMustHaveTenant)e).TenantId == CurrentTenantId));
    }

    return expression;
}

What I'm achiving here to combine soft delete and multitenant filters based on implemented interfaces of entities, as can be understood easily.

I'm using this PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) to create the expression.

IsSoftDeleteFilterEnabled, IsMayHaveTenantFilterEnabled, CurrentTenantId... are properties of my dbcontext.

Problem

The problem is !IsSoftEnabled (and other boolean flags) is not properly working. It caches the first dbcontext instance and never called again for later dbcontext instances. But CurrentTenantId property is properly called (there is interesting thing here: It's called one more time for each different query, before the actual query - I suppose it's for caching the query, but no problem).

The interesting this is that, when I compare IsSoftEnabled value with a property of the entity, it starts working. I suppose when we compare it via an entity property (like IsSoftDeleteFilterEnabled == e.IsDeleted || !((ISoftDelete) e).IsDeleted - this is just a stupid example) it does not grab value, but gets the expression property.

For this reason, I can not properly create a boolean flag to disable/enable a filter individually.

@hikalkan
Copy link
Author

hikalkan commented Aug 22, 2017

Additional information:

This does not work (as I said above):

e => !IsSoftDeleteFilterEnabled || !((ISoftDelete) e).IsDeleted

IsSoftDeleteFilterEnabled is only called one time, not for all queries. It somehow caches the value (or dbcontext instance)

But this works:

e => !((ISoftDelete) e).IsDeleted || ((ISoftDelete)e).IsDeleted != IsSoftDeleteFilterEnabled

By the magic of logical expressions, both expressions are actually identical (you can proove it) and I'm using this workaround. However I'm not sure the second one produce good & optimum SQL.

@anpete
Copy link
Contributor

anpete commented Oct 20, 2017

@smitpatel This look like a dupe of #9825?

@ajcvickers ajcvickers removed this from the 2.1.0-preview1 milestone Apr 26, 2018
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants