EF Core Global Query Filters: A Complete Guide
How to Write Cleaner, Safer, and More Maintainable EF Core Queries
When working with Entity Framework Core, it’s common to repeatedly filter out soft-deleted or archived records. Maybe you only want to show active customers, valid products, or non-archived documents.
Instead of remembering to add these conditions everywhere, EF Core gives us a powerful tool to automate this logic: Global Query Filters.
In this article, we’ll explore what they are, why they matter, and how to use them effectively—including a practical soft-delete example you can copy into your own project.
What Are Global Query Filters?
A global query filter is a LINQ expression automatically applied to an entity every time EF Core generates a query.
Once defined:
You don’t have to add the filter manually to each query
EF Core injects the filter into all queries, including navigation loads and LINQ queries
You can still bypass the filter when needed
This leads to cleaner, safer, and more maintainable code especially when dealing with soft deletes, permissions, or multi-tenant data.
The Soft Delete Scenario
Soft deletion is extremely common. Instead of physically deleting a record from the database, you mark it as deleted:
public class Customer
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
}Without global filters, every query would need:
.Where(c => !c.IsDeleted)And it’s only a matter of time before someone forgets it.
Applying a Global Query Filter
Global filters are configured inside OnModelCreating.
Here’s your example in full:
public class CustomerContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Global query filter for soft delete
modelBuilder.Entity<Customer>()
.HasQueryFilter(p => !p.IsDeleted);
}
}From this moment on, EF Core automatically adds:
WHERE IsDeleted = 0to every query involving Customer.
✅ Using Queries with the Filter Applied
// Filtered query: soft-deleted customers are excluded
var activeCustomers = await context.Customers
.ToListAsync(cancellationToken);Even though you didn’t specify a condition, EF Core did it for you behind the scenes.
This ensures your application never accidentally exposes deleted or archived records.
Bypassing the Filter When Needed
Sometimes you need access to all customers—for example, an admin tool, an audit job, or a restore action.
EF Core makes that easy:
// Unfiltered query: includes soft-deleted customers
var customers = await context.Customers
.IgnoreQueryFilters()
.ToListAsync(cancellationToken);This gives you full control while still keeping your main queries safe.
More Advanced: Named Global Query Filters (EF Core 10)
EF Core 10 introduces named global filters, letting you toggle specific filters on and off (similar to feature flags for filtering).
This is especially useful when you have multiple filters on the same entity, such as:
IsDeleted == falseIsArchived == falseTenantId == CurrentTenant
You can selectively disable only one filter instead of removing all of them via IgnoreQueryFilters().
This feature comes from a great community discussion and design proposal—if you’re curious, Tim Deschryver provides a deep dive here: (link you provided).
Why Global Query Filters Are So Powerful
The benefits that scale with your application
Centralized filtering logic
Prevents accidental data exposure
Great for soft delete, multi-tenancy, and security rules
Applies to LINQ queries and navigation properties
Once you start using them, it’s hard to imagine building an EF Core application without them.
Common Pitfalls to Avoid
Filters are applied to navigation properties, which may cause unexpected query results if you’re not aware.
Owned entity types can’t have filters.
Filters are cached per model, so dynamic per-request values require storing state in the DbContext (e.g., current tenant).
Looking Ahead: Named Filters in EF Core 10
Fine-grained control for advanced scenarios
EF Core 10 introduces named global query filters, allowing developers to disable specific filters instead of all filters at once.
This is especially useful when combining:
Soft delete
Archiving
Multi-tenancy
If you’re curious about the detailed proposal and examples, check out the original discussion referenced in your link.
Final Thoughts
Global Query Filters are one of EF Core’s most elegant ways to simplify your code and enforce data rules consistently. For scenarios like soft delete, they provide:
Cleaner code
Safer access patterns
More maintainable systems
Start with a simple soft-delete filter like the one above, and soon you’ll find ways to use them across your entire application.
👉 Full working code available at:
🔗https://sourcecode.kanaiyakatarmal.com/EFCoreGlobalQueryFilters
I hope you found this guide helpful and informative.
Thanks for reading!
If you enjoyed this article, feel free to share it and follow me for more practical, developer-friendly content like this.



Thanks for share it