Explore Global Query Filters in EF Core
In this article we are going to check one of the features of Entity Framework Core, Global Query Filters; this was introduced first in EF Core 2.0 and is just a query predicate that will be appended to the end of where clause for queries on entities for which this feature has been activated. Some common scenarios would be
Soft delete and
Consider that you are writing an application in which entities can be soft deleted, why not completely delete those entities? just don’t do that, said Udi Dahan. Okay, let’s create an
public class Author
If we want to add a query filter to the
Author entity, that should be done either in
OnModelCreating method of the
DbContext, or in the
EntityTypeConfiguration<T> class related to entity
T. For now, we could create a
DbContext and override its
OnModelCreating method, then configure the
Author entity by telling the context to automatically filter out soft-deleted records, their
IsDeleted property is
public class BookstoreDbContext : DbContext
To achieve that,
HasQueryFilter method is being used, it is defined on
EntityTypeBuilder and takes an
Func<Author, bool> which means it will take an author instance and returns a boolean based on the conditions defined, in this case, the author not being (soft) deleted. Now, whenever you query the
Author entity this query will also get appended to whatever you have provided for your where clause by the DbContext.
// omitted code
resulting in a database query:
So far so good. This could be a common scenario for almost all of your entities(aggregate roots, if interested) and we are reluctant to repeat same code for every individual entity(DRY).
Let’s first extract an interface,
ICanBeSoftDeleted, which desired entities will implement that.
public interface ICanBeSoftDeleted
Now we have to configure the common query filter for each entity, in the previous version we used a generic overload of
modelBuilder.Entity<T> method, now it is not possible though, so we have to generate a Lambda Expression for each entity to be able to use the non-generic overload:
protected override void OnModelCreating(ModelBuilder modelBuilder)
let’s discover the
GenerateQueryFilterLambda, it takes the type of the entity and will return a LambdaExpression of Func<Type, bool>, we should generate
e => e.IsDeleted == false, right? see how to generate each part using Expressions in .Net Core.
private LambdaExpression GenerateQueryFilterLambda(Type type)
Comments on top of each line indicating that what part of the (lambda) expression is going to be generated. This way we can simply implement the interface and our DbContext automatically detect and add the common global filter to our queries for the specified entities. At the end whenever you want to disable query filter use
IgnoreQueryFilters() on your LINQ query.
var authors = context.Authors
Most of the times there are business query patterns that will apply globally on some entities in you application, by employing
Query Filters of EF Core you could simply and easily implement such requirement. There is also a limitation, these filters can only be applied to the root entity of an inheritance hierarchy. Finally, here you could find a sample for this article. Have a great day and enjoy coding.