Язык программирования C#9 и платформа .NET5
Придерживаясь в книге темы автомобилей, предположим, что все записи
, которые не являются управляемыми, должны отфильтровываться из нормальных запросов. Вот как можно добавить глобальный фильтр запросов с использованием Fluent API:CarmodelBuilder.Entity<Car>(entity =>{<b> entity.HasQueryFilter(c => c.IsDrivable == true);</b>entity.Property(p => p.IsDrivable).HasField("_isDrivable").HasDefaultValue(true);});Благодаря такому глобальному фильтру запросов запросы, вовлекающие сущность
, будут автоматически отфильтровывать неуправляемые автомобили. Скажем, запуск следующего запроса LINQ:Carvar cars = Context.Cars.ToList();приводит к выполнению показанного ниже оператора SQL:
SELECT [i].[Id], [i].[Color], [i].[IsDrivable], [i].[MakeId],[i].[PetName], [i].[TimeStamp]FROM [Dbo].[Inventory] AS [i]WHERE [i].[IsDrivable] = CAST(1 AS bit)Если вам нужно просмотреть отфильтрованные записи, тогда добавьте в запрос LINQ вызов
, который отключает глобальные фильтры запросов для каждой сущности в запросе LINQ. Запуск представленного далее запроса LINQ:IgnoreQueryFilters()var cars = Context.Cars.IgnoreQueryFilters().ToList();инициирует выполнение следующего оператора SQL:
SELECT [i].[Id], [i].[Color], [i].[IsDrivable], [i].[MakeId],[i].[PetName], [i].[TimeStamp]FROM [Dbo].[Inventory] AS [i]Важно отметить, что вызов
удаляет фильтр запросов для всех сущностей в запросе LINQ, в том числе и тех, которые задействованы в вызовахIgnoreQueryFilters()илиInclude().Thenlnclude()Глобальные фильтры запросов на навигационных свойствах
Глобальные фильтры запросов можно также устанавливать на навигационных свойствах. Пусть вам необходимо отфильтровать любые заказы, которые содержат экземпляр
, представляющий неуправляемый автомобиль. Фильтр создается на навигационном свойствеCarсущностиCarNavigation:OrdermodelBuilder.Entity<Order>().HasQueryFilter(e => e.CarNavigation.IsDrivable);При выполнении стандартного запроса LINQ любые заказы, содержащие неуправляемый автомобиль, будут исключаться из результата. Ниже показан оператор LINQ и генерированный оператор SQL:
// Код C#var orders = Context.Orders.ToList();/* Сгенерированный запрос SQL */SELECT [o].[Id], [o].[CarId], [o].[CustomerId], [o].[TimeStamp]FROM [Dbo].[Orders] AS [o]INNER JOIN (SELECT [i].[Id], [i].[IsDrivable]FROM [Dbo].[Inventory] AS [i]WHERE [i].[IsDrivable] = CAST(1 AS bit)) AS [t]ON [o].[CarId] = [t].[Id]WHERE [t].[IsDrivable] = CAST(1 AS bit)Для удаления фильтра запросов используйте вызов
. Вот как выглядит модифицированный оператор LINQ и сгенерированный запрос SQL:IgnoreQueryFilters()// Код C#var orders = Context.Orders.IgnoreQueryFilters().ToList();/* Сгенерированный запрос SQL */SELECT [o].[Id], [o].[CarId], [o].[CustomerId], [o].[TimeStamp]FROM [Dbo].[Orders] AS [o]Здесь уместно предостеречь: исполняющая среда EF Core не обнаруживает циклические глобальные фильтры запросов, поэтому при добавлении фильтров запросов к навигационным свойствам соблюдайте осторожность.
Явная загрузка с глобальными фильтрами запросов
Глобальные фильтры запросов действуют и при явной загрузке связанных данных. Например, если вы хотите загрузить записи
дляCar, то фильтрMakeпредотвратит загрузку в память записей, представляющих неуправляемые автомобили. В качестве примера взгляните на следующий фрагмент кода:IsDrivablevar make = Context.Makes.First(x => x.Id == makeId);Context.Entry(make).Collection(c=>c.Cars).Load();К настоящему моменту не должен вызывать удивление тот факт, что сгенерированный оператор SQL включает фильтр для неуправляемых автомобилей:
SELECT [i].[Id], [i].[Color], [i].[IsDrivable],[i].[MakeId], [i].[PetName], [i].[TimeStamp]FROM [Dbo].[Inventory] AS [i]WHERE ([i].[IsDrivable] = CAST(1 AS bit)) AND ([i].[MakeId] = 1С игнорированием фильтров запросов при явной загрузке данных связана небольшая загвоздка. Возвращаемым типом метода
являетсяCollection(), который явно не реализует интерфейсCollectionEntry<Make,Car>. Чтобы вызватьIQueryable<T>, сначала потребуется вызвать методIgnoreQueryFilters(), который возвращает экземпляр реализацииQuery():IQueryable<Car>var make = Context.Makes.First(x => x.Id == makeId);Context.Entry(make).Collection(c=>c.Cars).Query().IgnoreQueryFilters().Load();