HomeNikola Knezevic
Banner

Apply Global Query Filters in EF Core

20 Mar 2025
4 min

Sponsor Newsletter

When working with databases, it’s common to need consistent filtering across multiple queries.

Without a built-in solution, we often have to manually apply filters in every query, increasing the risk of inconsistencies and missing filters.

This repetitive logic not only adds complexity but also makes the code harder to maintain.

To address this, Entity Framework Core introduces Query Filters.

EF Core Query Filters

Query Filters allows us to define global filtering rules at the entity level, ensuring they are consistently applied across all queries.

They are basically LINQ query predicates that are automatically applied to entity types at the metadata level.

Once defined, EF Core ensures that these filters are automatically applied to all queries involving the specified entity types. This includes not only direct queries but also entities retrieved through navigation properties or the include method.

Common Use Cases for Query Filters:

  • Soft Delete - Automatically exclude entities where IsDeleted = true
  • Multi-tenancy - Restrict data access based on a TenantId, ensuring users only access their own data.

In this blog post, we'll take a closer look at the Product entity.

csharp
public sealed class Product
{
    public Guid Id { get; set; }
    
    public string Name { get; set; }
    
    public string Description { get; set; }
    
    public decimal Price { get; set; }

    public bool IsDeleted { get; set; }


    public Product(string name, string description, decimal price)
    {
        Id = Guid.NewGuid();
        Name = name;
        Description = description;
        Price = price;
    }

    public void Update(string description, decimal price)
    {
        Description = description;
        Price = price;
    }

    public void Delete() => IsDeleted = true;
}

The Product entity supports soft deletion, meaning it won’t be physically removed from the database. Instead, its IsDeleted property will be set to true when a delete action occurs.

This is useful when you need to retain data for auditing, recovery or historical reference while preventing it from appearing in regular queries.

Without a query filter, we would have to manually add a condition to every query to exclude products where the IsDeleted property is set to true:

csharp
var product = await dbContext.Products
    .FirstOrDefaultAsync(product =>
        !product.IsDeleted &&
        product.Id == id);

This brings us to a common problem: the risk of forgetting to include shared conditions in queries.

Query filters easily solve this problem. They can be set in the OnModelCreating method or in the EntityTypeConfiguration by calling the HasQueryFilter method and passing the common condition:

csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .HasQueryFilter(product => !product.IsDeleted);
}

With the query filter in place, our queries no longer need to include the common condition:

csharp
var product = await dbContext.Products
    .FirstOrDefaultAsync(product => product.Id == id);

NOTE: You can only set one query filter per entity. If you have multiple conditions, you'll need to chain them together using && in the expression.

Ignore Query Filters

Just because we have a common check doesn’t mean it must always be applied.

When we want to disable the query filter, all we need to do is use IgnoreQueryFilters for that specific query and the filter will not be applied.

csharp
var products = await dbContext.Products
    .IgnoreQueryFilters()
    .ToListAsync();

Conclusion

Consistent filtering across multiple queries is essential when working with databases.

Entity Framework Core's Query Filters provide a simple and effective solution to this problem by allowing global filtering rules to be applied at the entity level.

By using query filters, you can automatically exclude soft-deleted records, enforce multi-tenancy and apply other common conditions.

EF Core also offers the flexibility to disable query filters for specific queries when needed, using IgnoreQueryFilters.

If you want to check out examples I created, you can find the source code here:

Source Code

I hope you enjoyed it, subscribe and get a notification when a new blog is up!

Subscribe

Stay tuned for valuable insights every Thursday morning.