Фильтры запросов уровня модели
Фильтры запросов уровня модели (Model-level query filters) позволяют определить предикат запроса LINQ непосредственно в метаданных модели (обычно в методе OnModelCreating контекста данных). Такие фильтры автоматически применяются к любым запросам LINQ, в которых используются классы, для которых определен фильтр.
Пусть у нас определены следующие классы:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int RoleId { get; set; }
public Role Role { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
}
Здесь класс пользователя имеет ссылку на класс роли, к которой он принадлежит. И также определим контекст данных:
public class ApplicationContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public int RoleId { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasQueryFilter(u => u.Age > 17 && u.RoleId == this.RoleId);
}
}
В метод HasQueryFilter() передается предикат, которому должен удовлетворять объект User, чтобы быть извлеченным из базы данных. То есть в результате запросов будут извлекаться только те объекты User, у которых значение свойства Age больше 17, а свойство RoleId равно значению свойства RoleId их контекста данных.
Используем данные классы:
using (ApplicationContext db = new ApplicationContext())
{
// пересоздадим базу данных
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
Role adminRole = new Role { Name = "admin" };
Role userRole = new Role { Name = "user" };
User user1 = new User { Name = "Tom", Age = 17, Role = userRole };
User user2 = new User { Name = "Bob", Age = 18, Role = userRole };
User user3 = new User { Name = "Alice", Age = 19, Role = adminRole };
User user4 = new User { Name = "Sam", Age = 20, Role = adminRole };
db.Roles.AddRange(userRole, adminRole);
db.Users.AddRange(user1, user2, user3, user4);
db.SaveChanges();
}
using (ApplicationContext db = new ApplicationContext() { RoleId = 2 })
{
var users = db.Users.Include(u => u.Role).ToList();
foreach (User user in users)
Console.WriteLine($"Name: {user.Name} Age: {user.Age} Role: {user.Role?.Name}");
}
Результатом будет следующий консольный вывод:
Name: Alice Age:19 Role:admin Name: Sam Age:20 Role:admin
То есть только два объекта из добавленных четырех соответствуют тому предикату, который был передан в HasQueryFilter. И данный фильтр будет действовать для всех запросов к базе данных, которые извлекают данные из таблицы Users. Например, нахождение минимального возраста:
using (ApplicationContext db = new ApplicationContext() { RoleId = 2 })
{
int minAge = db.Users.Min(x => x.Age);
Console.WriteLine(minAge); // 19
}
Несмотря на то, что минимальный возраст по всем 4 объектам составляет 17, но так как действует фильтр, при запросе будут учитываться только те объекты в бд, которые соответствуют фильтру.
Если необходимо во время запроса отключить фильтр, то применяется метод IgnoreQueryFilters():
using (ApplicationContext db = new ApplicationContext() { RoleId = 2 })
{
int minAge = db.Users.IgnoreQueryFilters().Min(x => x.Age);
Console.WriteLine(minAge); // 17
}
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.