Did You Hear About Query Filters In Entity Framework Core?

One of the most eagerly anticipated entity framework enhancements. You can filter the add configuration globally, which will filter every query obtained from the database using the entity framework, using the Entity Framework Global Query Filter.

By the name itself, you can realize the use of this feature. You are adding data filtration criteria on a global level. So you don’t have to write the same code condition everywhere in the project.

Let’s create a simple class in the application that includes a few properties, primarily the important filtering property called IsActive. This helps us to filter the non-active employees from the database.

using System;
using System.Collections.Generic;
using System.Text;
namespace EfCoreDemo {
    public class Employee {
        public int Id {
            get;
            set;
        }
        public string Name {
            get;
            set;
        }
        public int Age {
            get;
            set;
        }
        public string ContactNo {
            get;
            set;
        }
        public bool IsActive {
            get;
            set;
        }
    }
}

Suppose we want to add a query filter to the Employee entity. In that case, that should be done either in the 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 filter out soft-deleted records automatically; their IsActive property is true. Seed the Employee data to the database. In the example below, I added 4 records, with the first two as IsActive is true and the second as IsActive is false.

public partial class EmployeeContext: DbContext {
    public EmployeeContext(DbContextOptions options): base(options) {}
    public DbSet < Employee > Authors {
        get;
        set;
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        modelBuilder.Entity < Employee > ().HasQueryFilter(c => c.IsActive);
        base.OnModelCreating(modelBuilder);
        modelBuilder.Seed();
    }
}
public static class ModelBuilderExtension {
    public static void Seed(this ModelBuilder modelBuilder) {
        modelBuilder.Entity < Employee > ().HasData(new Employee {
            Id = 1, Name = "Jay", Age = 27, ContactNo = 99999999, IsActive = true
        }, new Employee {
            Id = 2, Name = "Krishna", Age = 26, ContactNo = 88888888, IsActive = true
        }, new Employee {
            Id = 3, Name = "Reddy", Age = 25, ContactNo = 88888888, IsActive = false
        }, new Employee {
            Id = 4, Name = "Majji", Age = 26, ContactNo = 77777777, IsActive = false
        });
    }
}

To achieve that, HasQueryFilter, the method being used is defined on EntityTypeBuilder and takes an Expression of 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 be appended to whatever you provided for your where clause by the DbContext.

Create a Simple API to fetch all the employee records from the database.

[Route("api/[controller]")]
[ApiController]
public class EmployeeController: ControllerBase {
    public EmployeeContext _employeeContext;
    public EmployeeController(EmployeeContext employeeContext) {
            _employeeContext = employeeContext;
        }
        [HttpGet(nameof(GetEmployees))]
    public async Task < IActionResult > GetEmployees() {
        // By default Query Filters applied
        return Ok(await _employeeContext.Authors.ToListAsync());
    }
}

By default, we have enabled the HasQueryFilterin the DbContext, so it will only fetch the records which are IsActive = true.

Did you hear about Query Filters in Entity Framework Core ?

This way, we can implement the interface, and our DbContext automatically detects and add the common global filter to our queries for the specified entities. Ultimately, whenever you want to disable the query filter, use IgnoreQueryFilters() on your LINQ query.

[Route("api/[controller]")]
[ApiController]
public class EmployeeController: ControllerBase {
    public EmployeeContext _employeeContext;
    public EmployeeController(EmployeeContext employeeContext) {
            _employeeContext = employeeContext;
        }
        [HttpGet(nameof(GetEmployees))]
    public async Task < IActionResult > GetEmployees() {
        // If we want to ignore the Query Filters
        return Ok(await _employeeContext.Authors.IgnoreQueryFilters().ToListAsync());
    }
}

Source Code - GitHub

Conclusion

Most of the time, there are business query patterns that will apply globally to some entities in your application. By employing Query Filters EF Core, you could quickly implement such requirements. There is also a limitation. These filters can only be applied to the root entity of an inheritance hierarchy. 


Similar Articles