Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!
Шрифт:
Интервал:
Закладка:
Глобальные фильтры запросов
Глобальные фильтры запросов позволяют добавлять конструкцию where во все запросы LINQ для определенной сущности. Например, распространенное проектное решение для баз данных предусматривает использование "мягкого" удаления вместо "жесткого". В таблицу добавляется поле, указывающее состояние удаления записи. Если запись "удалена", то значение поля устанавливается в true (или 1), но запись из базы данных не убирается. Прием называется "мягким" удалением. Чтобы отфильтровать записи, повергнувшиеся "мягкому" удалению, от тех, которые обрабатывались нормальными операциями, каждая конструкция where обязана проверять значение поля с состоянием удаления записи. Включение такого фильтра в каждый запрос может занять много времени, да и не забыть о нем довольно проблематично.
Инфраструктура EF Core позволяет добавлять к сущности глобальный фильтр запросов, который затем применяется к каждому запросу, вовлекающему эту сущность. Для описанного выше примера с "мягким" удалением вы устанавливаете фильтр на сущностном классе, чтобы исключить записи, повергнувшиеся "мягкому" удалению. К любым создаваемым EF Core запросам, затрагивающим сущности с глобальными фильтрами запросов, будут применяться их фильтры. Вам больше не придется помнить о необходимости включения конструкции where в каждый запрос.
Придерживаясь в книге темы автомобилей, предположим, что все записи Car, которые не являются управляемыми, должны отфильтровываться из нормальных запросов. Вот как можно добавить глобальный фильтр запросов с использованием Fluent API:
modelBuilder.Entity<Car>(entity =>
{
entity.HasQueryFilter(c => c.IsDrivable == true);
entity.Property(p => p.IsDrivable).HasField("_isDrivable").
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<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)
Для удаления фильтра запросов используйте вызов 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 => 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();
Тот же процесс применяется в случае использования метода Reference() для извлечения данных из навигационного свойства типа коллекции.
Выполнение низкоуровневых запросов SQL с помощью LINQ
Иногда получить корректный оператор LINQ для компилируемого запроса сложнее, чем просто написать код SQL напрямую. К счастью, инфраструктура EF Core располагает механизмом, позволяющим выполнять низкоуровневые операторы SQL в DbSet<T>. Методы FromSqlRaw() и FromSqlRawInterpolated() принимают строку, которая становится основой запроса LINQ. Такой запрос выполняется на стороне сервера.
Если низкоуровневый оператор SQL не является завершающим (скажем, хранимой процедурой, пользовательской функцией или оператором, который использует общее табличное выражение или заканчивается точкой с запятой), тогда в запрос можно добавить дополнительные операторы LINQ. Дополнительные операторы LINQ наподобие конструкций Include(), OrderBy() или Where() будут объединены с первоначальным низкоуровневым обращением SQL и любыми глобальными фильтрами запросов, после чего весь запрос выполнится на стороне сервера.
При использовании одного из вариантов FromSql*() запрос должен формироваться с использованием схемы базы данных и имени таблицы, а не имен сущностей. Метод FromSqlRaw() отправит строку в том виде, в каком она записана. Метод FromSqlInterpolated() применяет интерполяцию строк C# и каждая интерполированная строка транслируется в параметр SQL. В случае использования переменных вы должны использовать версию с интерполяцией для обеспечения дополнительной защиты, присущей параметризованным запросам.
Предположим, что для сущности Car установлен глобальный фильтр запросов. Тогда показанный ниже оператор LINQ получит первую запись Inventory
Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.
Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.
- 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
- 2. Просьба отказаться от оскорблений, угроз и запугиваний.
- 3. Просьба отказаться от нецензурной лексики.
- 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.
Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.
Оставить комментарий
-
Гость Татьяна24 сентябрь 22:20 Как то не очень... Невеста по ошибке. Я не дам тебе развод - Майя Линн
-
Римма24 сентябрь 21:52 Почему главные героинитпкие идиотки? И сюжет не плохой, и написано хорошо. Но как героиня - так дура дурой.... Хозяйка маленького дома, или Любимая для дракона - Кира Рамис
-
Римма20 сентябрь 12:27 Много ненужных пояснений и отступлений. Весь сюжет теряет свою привлекательность. Героиня иногда так тупит, что читать не... Хозяйка приюта для перевертышей и полукровок - Елена Кутукова