Литмир - Электронная Библиотека
A
A

Придерживаясь в книге темы автомобилей, предположим, что все записи

Car
, которые не являются управляемыми, должны отфильтровываться из нормальных запросов. Вот как можно добавить глобальный фильтр запросов с использованием Fluent API:

modelBuilder.Entity<Car>(entity =>

{

<b>  entity.HasQueryFilter(c =&gt; c.IsDrivable == true);</b>

  entity.Property(p =&gt; p.IsDrivable).HasField(&quot;_isDrivable&quot;).

    HasDefaultValue(true);

});

Благодаря такому глобальному фильтру запросов запросы, вовлекающие сущность

Car
, будут автоматически отфильтровывать неуправляемые автомобили. Скажем, запуск следующего запроса LINQ:

var 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 вызов

IgnoreQueryFilters()
, который отключает глобальные фильтры запросов для каждой сущности в запросе LINQ. Запуск представленного далее запроса LINQ:

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]

Важно отметить, что вызов

IgnoreQueryFilters()
удаляет фильтр запросов для всех сущностей в запросе LINQ, в том числе и тех, которые задействованы в вызовах
Include()
или
Thenlnclude()
.

Глобальные фильтры запросов на навигационных свойствах

Глобальные фильтры запросов можно также устанавливать на навигационных свойствах. Пусть вам необходимо отфильтровать любые заказы, которые содержат экземпляр

Car
, представляющий неуправляемый автомобиль. Фильтр создается на навигационном свойстве
CarNavigation
сущности
Order
:

modelBuilder.Entity&lt;Order&gt;().HasQueryFilter(e =&gt; 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)

Для удаления фильтра запросов используйте вызов

IgnoreQueryFilters()
. Вот как выглядит модифицированный оператор LINQ и сгенерированный запрос SQL:

// Код 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
, то фильтр
IsDrivable
предотвратит загрузку в память записей, представляющих неуправляемые автомобили. В качестве примера взгляните на следующий фрагмент кода:

var make = Context.Makes.First(x =&gt; x.Id == makeId);

Context.Entry(make).Collection(c=&gt;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&lt;Make,Car&gt;
, который явно не реализует интерфейс
IQueryable&lt;T&gt;
. Чтобы вызвать
IgnoreQueryFilters()
, сначала потребуется вызвать метод
Query()
, который возвращает экземпляр реализации
IQueryable&lt;Car&gt;
:

var make = Context.Makes.First(x =&gt; x.Id == makeId);

Context.Entry(make).Collection(c=&gt;c.Cars).Query().IgnoreQueryFilters().Load();

425
{"b":"847442","o":1}