SkillAgentSearch skills...

EntityFramework.DynamicFilters

Global filtering for Entity Framework.

Install / Use

/learn @zzzprojects/EntityFramework.DynamicFilters
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

What's Entity Framework Dynamic Filters?

Create global and scoped filters for Entity Framework queries. The filters are automatically applied to every query and can be used to support use cases such as Multi-Tenancy, Soft Deletes, Active/Inactive, etc.

Filters can be created using boolean LINQ expressions and also support the Contains() operator.

Access to DynamicFilters is done via extension methods in the EntityFramework.DynamicFilters namespace on the DbContext and DbModelBuilder classes.

Supports MS SQL Server (including Azure), MySQL, Oracle (*see notes below), and PostgreSQL.

Read more on our Website.

Downloads

nuget nuget

PM> NuGet\Install-Package EntityFramework.DynamicFilters
> dotnet add package EntityFramework.DynamicFilters

Do it support EF Core?

NO, it doesn't support EF Core and there is no plan to support it.

EF Core already have their one global query filter that will eventually be evolved in Named query filter

Sponsors

ZZZ Projects owns and maintains Entity Framework Dynamic Filters as part of our mission to add value to the .NET community

Through Entity Framework Extensions and Dapper Plus, we actively sponsor and help key open-source libraries grow.

Entity Framework Extensions

Dapper Plus

Changes in Version 2

  • Added support for creating filters that reference child classes/navigation properties. See Issue #65 for more details. Requires that FK properties are defined on the models. It also includes support for Any() and All() on child collections.
  • Filter parameter values can now reference the current DbContext instance. See Parameter Expressions.
  • Filters can be enabled conditionally via a delegate, just like parameter values. See Conditionally Enabling Filters.
  • Added options to filters to control how/when they are applied to entities. See Filter Options

Putting this all together, you can now do the following:

modelBuilder.Filter("NotesForCompany", (Note n, int orgID) => n.Person.OrganizationID==orgID, (MyContext ctx) => ctx.CurrentOrganizationID);
modelBuilder.EnableFilter("UserOrg", (MyContext ctx) => !ctx.UserIsAdmin);

This will create a filter to restrict queries on the Notes table to only those records made by people in the current users Organization. The filter will only be enabled if the current user is not an Administrator. And both expressions access properties in the current DbContext instance.

Defining Filters

Filters are defined in DbContext.OnModelCreating().

Filters should always follow any other model configuration - including the call to the base.OnModelCreating() method. It is best to make the filter definitions the final step of OnModelCreating() to make sure that they are not in effect until the entire model is fully configured.

All filters have global scope and will be used by all DbContexts. Each DbContext can also choose to provide a "scoped" filter value or can disable the filter via the DisableFilter() extension method. Scoped parameter changes and filter disabling will apply only to that DbContext and do not affect any existing or future DbContexts.

Filters can be defined on a specific entity class or an interface. Below is an example of a "soft delete" filter created on an ISoftDelete interface. This filter will apply to any entity that implements ISoftDelete and will automatically filter those entities by applying the condition "IsDeleted==false".

modelBuilder.Filter("IsDeleted", (ISoftDelete d) => d.IsDeleted, false);

Filter values can also be provided via a delegate/expression instead of a specific value (as shown in the above example). This can allow you to vary the parameter value dynamically. For example, a filter can be created on the UserID and be provided per http request. Below is an example that obtains a "Person ID" from the Thread.CurrentPrincipal. This delegate will be evaluated each time the query is executed, so it will obtain the "Person ID" associated with each request.

modelBuilder.Filter("Notes_CurrentUser", (Note n) => n.PersonID, () => GetPersonIDFromPrincipal(Thread.CurrentPrincipal));

In this example, the Note entity is "owned" by the current user. This filter will ensure that all queries made for Note entities will always be restricted to the current user, and it will not be possible for users to retrieve notes for other users.

Parameter Expressions

As of Version 2, parameter delegate expressions can be specified as either a Func<object> (as shown above) or a Func<DbContext, object> like this:

modelBuilder.Filter("Notes_CurrentUser", (Note n) => n.PersonID, (MyContext ctx) => ctx.CurrentPersonID);

This allows the parameter value expressions to reference the current DbContext instance. In this example, the value of the parameter will be set to the value of the CurrentPersonID property in the current MyContext instance.

Linq Filters

Filters can also be created using LINQ conditions and with multiple parameters.

This Filter() command creates a filter that limits BlogEntry records by AccountID and an IsDeleted flag. A parameter is created for each condition with parameter names "accountID" and "isDeleted":

modelBuilder.Filter("BlogEntryFilter", 
                    (BlogEntry b, Guid accountID, bool isDeleted) => (b.AccountID == accountID) && (b.IsDeleted == isDeleted), 
                    () => GetPersonIDFromPrincipal(Thread.CurrentPrincipal),
                    () => false);

The linq syntax is somewhat limited to boolean expressions but does support the Contains() operator on Enumerable<T> to generate sql "in" clauses:

var values = new List<int> { 1, 2, 3, 4, 5 };
modelBuilder.Filter("ContainsTest", (BlogEntry b, List<int> valueList) => valueList.Contains(b.IntValue.Value), () => values);

If you require support for additional linq operators, please create an issue.

Changing Filter Parameter Values

Within a single DbContext instance, filter parameter values can also be changed. These changes are scoped to only that DbContext instance and do not affect any other DbContext instances.

To change the Soft Delete filter shown above to return only deleted records, you could do this:

context.SetFilterScopedParameterValue("IsDeleted", true);

If the filter contains multiple parameters, you must specify the name of the parameter to change like this:

context.SetFilterScopedParameterValue("BlogEntryFilter", "accountID", 12345);

Parameter values can be set to a specific value or delegate expressions (Func<object> or Func<DbContext, object>).

Global parameter values can also be changed using the SetFilterGlobalParameterValue extension methods.

Enabling and Disabling Filters

To disable a filter, use the DisableFilter extension method like this:

context.DisableFilter("IsDeleted");

Filters can also be globally disabled after they are created in OnModelCreating:

modelBuilder.DisableFilterGlobally("IsDeleted");

Globally disabled filters can then be selectively enabled as needed. Enabling a globally disabled filter will apply only to that DbContext just like scoped parameter values.

context.EnableFilter("IsDeleted");

You can also mass enable/disable all filters within a DbContext at once:

context.DisableAllFilters();
context.EnableAllFilters();

However, note that if a query is executed with a filter disabled, Entity Framework will cache those entities internally. If you then enable a filter, cached entities may be included in child collections that otherwise should not be. Entity Framework caches per DbContext, so if you find this to be an issue, you can avoid it by using a fresh DbContext.

In order to be able to dynamically enable/disable filters, a special condition is added to the sql query that will look something like:

OR (@DynamicFilterParam_000001 IS NOT NULL)

If the filter is enabled, this condition is dynamically excluded from the sql just before execution but will be present when the filter is disabled (and the parameter value will be set to 1). In both cases, the parameter will be listed in the parameter list sent in the query.

If you never require the need to enable or disable filters at any time during the application life cycle, you can prevent this condition entirely using these two methods:

modelBuilder.PreventDisabledFilterConditions("IsDeleted");  // disable a single filter
modelBuilder.PreventAllDisabledFilterConditions();          // disable all filters defined up to calling this method

This can only be done during OnMod

View on GitHub
GitHub Stars502
CategoryDevelopment
Updated1mo ago
Forks84

Languages

C#

Security Score

95/100

Audited on Feb 13, 2026

No findings