# How To Use Global Query Filters in EF Core

> In this week's newsletter, I'll show you how to remove repetitive conditions from your EF Core queries, like the soft-delete check or the tenantId filter you repeat in every query. EF Core has a powerful feature called Query Filters that can do it for you.

Published: 2022-10-29. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/how-to-use-global-query-filters-in-ef-core

A global query filter is a condition you configure once with `HasQueryFilter` inside `OnModelCreating`, and EF Core applies it to every query for that entity type.
It removes repetitive conditions like the soft-delete check or a `tenantId` filter from your queries.
Call `IgnoreQueryFilters` when a single query needs to skip it.

In this week's newsletter, I'll show you how you can remove repetitive conditions in **EF Core** database queries.

Which kinds of queries fit this description?

An example would be when you implement [**soft-delete**](https://milanjovanovic.tech/blog/implementing-soft-delete-with-ef-core), and have to check if a record was **soft-deleted** or not in every query.

Also, it's practical if you're working in a [**multi-tenant system**](https://milanjovanovic.tech/blog/multi-tenant-applications-with-ef-core) and need to specify a `tenantId` on every query.

**EF Core** has a powerful feature that can help you remove repetitive conditions from your code.

I'm talking about [Query Filters](https://learn.microsoft.com/en-us/ef/core/querying/filters).

Let's see how we can implement it.

## How To Apply Query Filters

Before introducing **Query Filters**, we will see how the standard approach looks.
We have an `Orders` table that supports **soft-deleting**.
And we never want to return **soft-deleted** orders.

We'll start with an `Order` entity that has an `IsDeleted` property.

```csharp
public class Order
{
   public int Id { get; set; }
   public bool IsDeleted { get; set; }
}
```

And we have a business requirement that we can only query orders that are not deleted.

Here's what an **EF** query to get a single `Order` might look like:

```csharp
dbContext
   .Orders
   .Where(order => !order.IsDeleted)
   .Where(order => order.Id == orderId)
   .FirstOrDefault();
```

This works perfectly for what we need to do.

However, we need to remember to apply this condition every time we want to query the `Order` entity.

Now, let's see how we can define a **Query Filter** on the `Order` entity to
apply this check when querying the database.

Inside of the `OnModelCreating` method on the database context, we need to
call the `HasQueryFilter` method and specify the expression we want:

```csharp
modelBuilder
   .Entity<Order>()
   .HasQueryFilter(order => !order.IsDeleted);
```

Now we can omit the **soft-delete** check from the previous **LINQ** expression:

```csharp
dbContext
   .Orders
   .Where(order => order.Id == orderId)
   .FirstOrDefault();
```

And this is the **SQL** that **EF** will generate with the **Query Filter**:

```sql
SELECT o.*
FROM Orders o
WHERE o.IsDeleted = FALSE AND o.Id = @orderId
```

## Disabling Query Filters

You may run into a situation where you need to disable **Query Filters** for a specific query.
Luckily, there is an easy way to do this.

In your **LINQ** expression, you need to call the `IgnoreQueryFilters` method,
and all the **Query Filters** configured for this entity will be disabled:

```csharp
dbContext
   .Orders
   .IgnoreQueryFilters()
   .Where(order => order.Id == orderId)
   .FirstOrDefault();
```

Be careful when doing this, as you can easily introduce unwanted behavior in your application.

## Good Things To Know Before Using Query Filters

Here are a few more details that you should know about **Query Filters** before using them.
Hopefully, this will save you some trouble if you decide to use them in your application.

**Configuring multiple Query Filters**

Configuring multiple **Query Filters** on the same entity will only apply the last one.
If you need more than one condition, you can do that with the logical `AND` operator (&&).

**Ignoring specific Query Filters**

If you need to ignore a specific expression in a **Query Filter** and leave the rest in place,
unfortunately, you can't do that. Only one **Query Filter** is allowed per entity type.

One solution is calling `IgnoreQueryFilters`, which will remove the configured **Query Filter**
for that entity type. And then manually apply the condition that you need for that specific query.

---

## Frequently asked questions

### What are global query filters in EF Core?

A global query filter is a condition, configured with HasQueryFilter inside OnModelCreating, that EF Core automatically applies to every query for that entity type. It removes repetitive conditions, like soft-delete checks, from your LINQ queries.

### How do you implement soft delete with EF Core query filters?

Give the entity an IsDeleted property and configure HasQueryFilter with the condition that excludes deleted rows. Every query then omits soft-deleted records automatically, and the generated SQL adds the IsDeleted check to the WHERE clause alongside your other conditions.

### How do you disable a query filter for a specific query?

Call IgnoreQueryFilters in the LINQ expression, which disables all query filters configured for that entity. Be careful, because this can easily introduce unwanted behavior, such as returning soft-deleted records.

### Can an entity have multiple query filters in EF Core?

No, only one query filter is allowed per entity type, and configuring several applies just the last one. Combine conditions in a single filter with the logical AND operator (&&). To skip one condition selectively, call IgnoreQueryFilters and reapply the conditions you still need manually.

### When are EF Core query filters useful?

Whenever you repeat the same condition in every query: soft-delete checks that must exclude deleted records, or multi-tenant systems where every query needs to filter by a tenantId.
