Entity Framework Classic Query Filter
Description
The Query Filter feature allows you to filter returned entities from a query using a predicate (where clause).
public class EntityContext : DbContext { public EntityContext() : base(FiddleHelper.GetConnectionStringSqlServer()) { // Add your Global Query Filter here this.Configuration.QueryFilter.Filter<ISoftDelete>(customer => !customer.IsDeleted); } public DbSet<Customer> Customers { get; set; } } // SELECT * FROM Customers WHERE IsDeleted = 0 var list = context.Customers.ToList();
Try it: NET Core | NET Framework
The filter is applied in the database and application side:
- Database side: Whenever possible, the filter is applied in the SQL query.
- Application side: The filter is always applied to the query result.
This feature allows to exclude or include specific entities to handle scenarios such as:
What is supported?
All cases are supported:
- Include
- Lazy Loading
- Many to Many
- Etc.
Advantage
- Centralize logic in Query Filter instead of adding it on every queries
- Reduce the chance of missing a filter when creating a new query
- Improve code readability
- Improve development productivity
Getting Started
Global Query Filter
You can create a Global Query Filter inside your context constructor. This filter will be used by all your context instances.
public class EntityContext : DbContext { public EntityContext() : base(FiddleHelper.GetConnectionStringSqlServer()) { // Add your Global Query Filter here this.Configuration.QueryFilter.Filter<ISoftDelete>(customer => !customer.IsDeleted); } public DbSet<Customer> Customers { get; set; } } // SELECT * FROM Customers WHERE IsDeleted = 0 var list = context.Customers.ToList();
Try it: NET Core | NET Framework
Instance Query Filter
You can create an Instance Query Filter after a context instance has been created. This filter will be specific to this context instance. If your context instance already has query filter both filters will be enabled.
using (var context = new EntityContext()) { // Add your Instance Query Filter here context.Configuration.QueryFilter.Filter<ISoftDelete>(customer => !customer.IsDeleted); // SELECT * FROM Customers WHERE IsActive = 1 var list = context.Customers.ToList(); FiddleHelper.WriteTable("Customers", list); }
Try it: NET Core | NET Framework
Enable/Disable Query Filter
You can enable/disable your Query Filter with the Enable()
, Disable()
, EnableFilter(id)
, and DisableFilder(id)
methods.
using (var context = new EntityContext()) { var filter = context.Configuration.QueryFilter.Filter<ISoftDelete>(QueryFilterType.SoftDelete.ToString(), customer => !customer.IsDeleted); // QueryFilter.Disable() { filter.Disable(); // SELECT * FROM Customers var list = context.Customers.ToList(); FiddleHelper.WriteTable("Customers", list); } // QueryFilter.Enable() { filter.Enable(); // SELECT * FROM Customers WHERE IsActive = 1 var list = context.Customers.ToList(); FiddleHelper.WriteTable("Customers", list); } // QueryFilterManager.DisableFilter(string id) { // DOC: You can enable/disable your `QueryFilter` with the `Enable()`, `Disable()`, `EnableFilter(id)`, and `DisableFilder(id)` methods. context.Configuration.QueryFilter.DisableFilter(QueryFilterType.SoftDelete.ToString()); // SELECT * FROM Customers var list = context.Customers.ToList(); FiddleHelper.WriteTable("Customers", list); } // QueryFilterManager.EnableFilter(string id) { // DOC: You can enable/disable your `QueryFilter` with the `Enable()`, `Disable()`, `EnableFilter(id)`, and `DisableFilder(id)` methods. context.Configuration.QueryFilter.EnableFilter(QueryFilterType.SoftDelete.ToString()); // SELECT * FROM Customers WHERE IsActive = 1 var list = context.Customers.ToList(); FiddleHelper.WriteTable("Customers", list); } }
Try it: NET Core | NET Framework
DANGER:DO NOT disable
Global Query Filter
unless you want to disable the filter for all your context instances.
HINT:Use an
enum
when using a specified IDQueryFilterType.FilterName.ToString()
to avoid hardcoding astring
.
Real Life Scenarios
Soft Delete
Your application uses Soft Delete/Logical Delete to delete entities.
The Query Filter allows you to exclude all entities that are soft deleted from all your queries.
public class EntityContext : DbContext { public EntityContext() : base(FiddleHelper.GetConnectionStringSqlServer()) { // Add your Global Query Filter here this.Configuration.QueryFilter.Filter<ISoftDelete>(customer => !customer.IsDeleted); } public DbSet<Customer> Customers { get; set; } } // SELECT * FROM Customers WHERE IsDeleted = 0 var list = context.Customers.ToList();
Try it: NET Core | NET Framework
HINT:The filter is usually applied to an interface named
ISoftDelete
inherited by all entity types that use Soft Delete.
Multi-Tenancy
Your application uses a single instance to serve multiple tenants.
The Query Filter allows you to include only data that is related to the specified TenantID
to all your queries.
public static int ApplicationTenantID = 1; public class EntityContext : DbContext { public EntityContext() : base(FiddleHelper.GetConnectionStringSqlServer()) { // Add your Global Query Filter here this.Configuration.QueryFilter.Filter<ITenant>(x => x.TenantID == ApplicationTenantID); } public DbSet<Customer> Customers { get; set; } } // SELECT * FROM Customers WHERE TenantID = 1 var list = context.Customers.ToList();
Try it: NET Core | NET Framework
HINT:The filter is usually applied to an interface named
ITenant
inherited by all entity types that use multi-tenancy.
Logical Data Partitioning
Your application stores data in the same table but only a specific range should be available by example for a country.
The Query Filter allows you to include only data available for the specified country to all your queries.
// TODO // [Try it](8c3zgI)
Security Access
Your application has security access. The logged user can only view some data depending on his role.
The Query Filter
allows you to include only data the user has access to all your queries.
public static int CurrentRoleId = 1; // admin public class EntityContext : DbContext { public EntityContext() : base(FiddleHelper.GetConnectionStringSqlServer()) { this.Configuration.QueryFilter.Filter<ISoftDelete>(customer => !customer.IsDeleted || CurrentRoleId == 1); this.Configuration.QueryFilter.Filter<Customer>(customer => customer.Type == CustomerType.Web || CurrentRoleId == 1); } public DbSet<Customer> Customers { get; set; } }
Try it: NET Core | NET Framework
Documentation
QueryFilter
Properties
Name | Description | Example |
---|---|---|
ID |
Gets the QueryFilter ID. |
NET Core / NET Framework |
EntityType |
Gets the QueryFilter entity type on which the filter is applied. |
NET Core / NET Framework |
IsEnabled |
Gets if the QueryFilter is enabled. Use Enable() and Disable() method to change the state. Always return false if the QueryFilter feature is disabled. |
NET Core / NET Framework |
Methods
Name | Description | Example |
---|---|---|
Enable() |
Enable the QueryFilter . |
NET Core / NET Framework |
Disable() |
Disable the QueryFilter . |
NET Core / NET Framework |
QueryFilterManager
Properties
Name | Description | Example |
---|---|---|
IsEnabled |
Gets or sets if the QueryFilter feature is enabled. |
NET Core / NET Framework |
Methods
Name | Description | Example |
---|---|---|
Filter<T>(Expression<Func<T, bool>> filter) |
Filter an entity type using a predicate. | NET Core / NET Framework |
Filter<T>(string id, Expression<Func<T, bool>> filter) |
Filter an entity type using a predicate. The QueryFilter will be created with the specified ID. |
NET Core / NET Framework |
EnableFilter(string id) |
Enable the QueryFilter with the specified id. |
NET Core / NET Framework |
DisableFilter(string id) |
Disable the QueryFilter with the specified id. |
NET Core / NET Framework |
GetFilter(string id) |
Get the QueryFilter with the specified id. |
NET Core / NET Framework |
Limitations
Change Tracker
If an entity is already loaded in the ChangeTracker
, the filter may not apply due to how the ChangeTracker
works.
For example:
- You load a customer with all his invoices
- You add a filter to the invoice entity type
- You load the same customer with all his invoices
- The customer invoices have not been filtered
T