TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
.NET sh blog

22 Feb 2025, 12:32

Открыть в Telegram Поделиться Пожаловаться

EntityFrameworkCore потрясающий инструмент который сильно упрощает нам жизнь, но если не контролировать какие SQL запросы уходят в СУБД, то это может доставить боль при обновлениях мажорных версий, т.к. EF может в целом изменить подходы к построению SQL и что-нибудь сломать или сильно замедлить запросы из-за генерации неэффективных запросов.

А такое случается достаточно часто, несмотря даже на сумасшедшие 286 882 тестов, которые к сожалению всё равно не могут покрыть всевозможные сценарии и так или иначе будут просачиваться баги.

К примеру, несколько лет назад на одном проекте при апдейте с версии 2.2 на 3.0, у меня один запрос стал тянуть чуть ли не все данные из СУБД, из-за чего ему стало не хватать work_mem, поэтому он начал активно использовать диск и генерировал временные файлы. Но запрос выполнялся долго, отменялся по таймауту, но почему-то не подчищалась папка temp и таким образом диск быстро заполнялся и пришлось ребутать СУБД чтобы он не ушел в режим readonly.
Решилось всё переписыванием запроса с учетом особенностей уже версии 3.0.

Тогда же занесли еще один досадный баг, когда просто забыли рекурсивно пройтись по деревьям выражений из-за чего сломалось использование PredicateBuilder, а сам фикс был однострочным, но помню много времени ждал пока этот фикс доедет до релиза.
А из свежих, в 9 версии сломали GroupBy в некоторых кейсах.

Подобные проблемы регулярно встречаются и хорошо бы это покрыть тестами и недопустить проблемы до прода.

Самый простой способ тестирования генератора SQL запросов - это snapshot тесты.
В .NET есть крутая библиотека Verify и Verify.EntityFramework.
Используя его, мы можем встроиться в DbContext и с помощью интерцепторов записывать все исходящие SQL запросы и сохранить их как снепшот.
При апдейте версии EFCore или при изменении нашего кода, такие тесты покажут изменения в SQL запросах если они были.

Полноценного примера в доке нет, поэтому держите гайд:

1. В Composition Root (в проекте со Startup.cs или Program.cs) добавить зависимость от Verify.EntityFramework и вызвать метод расширения EnableRecording на DbContextOptionsBuilder. Его надо добавить только при запуске тестов:
builder.Services.AddDbContext((sp, options) =>
{
// тут настройка DbContext: options.UseNpgsql и т.п.

// при запуске интеграционных тестов окружение проставляю в IntegrationTests.
if (_env.EnvironmentName == "IntegrationTests" && options is DbContextOptionsBuilder o)
{
o.EnableRecording();
}
}

2. В сборке с интеграционными тестами подключить библиотеку Verify.NUnit/XUnit и инициализировать Verify.EntityFramework:
public static class ConfigureVerify
{
[ModuleInitializer]
public static void Init()
{
var model = GetDbModel();
VerifyEntityFramework.Initialize(model);
}

private static IModel GetDbModel()
{
var options = new DbContextOptionsBuilder();
options
.UseNpgsql("fake")
.UseSnakeCaseNamingConvention();
using var data = new ApplicationDbContext(options.Options);
return data.Model;
}
}

3. В тестах обернуть в using вызов тестируемого кода (всю секцию act)
using (Recording.Start())
{
// act
await sut.ExecuteAsync();
}

и вызывать Verify в качестве assert:
await Verify().AutoVerify(includeBuildServer: false);

После успешного прохода теста, появится *.verified.txt файл, в котором будут все отправленные SQL запросы в рамках тестируемого сценария:
{
ef: [
{
Type: ReaderExecutedAsync,
HasTransaction: true,
Text:
-- StrictOrderingOutboxRepository:LockAndReturnItemsBatchAsync

SELECT * FROM kafka_ef_outbox_items

ORDER BY id ASC
LIMIT 10
FOR UPDATE NOWAIT;
},
]
}
Если изменить код, добавить еще SQL вызовы или поменять их местами, то изменится и снепшот, который можно будет провалидировать и закоммитить в git репозиторий.
Если изменится SQL запрос, можно всегда его отсюда скопировать и сделать explain, посмотреть на план запроса и либо переписать либо оставить как есть.

566 0 10 1 23
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot