AsSplitQuery()
По некоторым моим предыдущим сообщениям понятно - я пилю свой проект. Пока подробности останутся в тайне😏 Но вот буквально вчера наткнулся на очень необычную ситацию. На моем компе все работает, на сервере нет. После того как поковырялся в логах выяснилось что если добавить AsSplitQuery в запрос EF то начинает раюотать. Что это такое ?
Представьте таблицы Posts (Посты), Comments (Комментарии) и Tags (Теги). У одного поста может быть много комментариев и много тегов. По умолчанию, когда вы пишете такой код: var posts = context.Posts .Include(p => p.Comments) // Включить коллекцию комментариев .Include(p => p.Tags) // Включить коллекцию тегов .ToList(); Entity Framework пытается быть эффективным и генерирует один большой SQL-запрос со множеством JOIN: -- БЕЗ AsSplitQuery(): ОДИН ГИГАНТСКИЙ ЗАПРОС SELECT * FROM Posts p LEFT JOIN Comments c ON p.Id = c.PostId LEFT JOIN Tags t ON p.Id = t.PostId; Если у поста 10 комментариев и 5 тегов, база данных вернет 10 * 5 = 50 строк для этого одного поста. Данные самого поста будут скопированы 50 раз.EF Core может "запутаться", пытаясь собрать из этой плоской каши данных правильные объекты, и в итоге ваши коллекции Comments или Tags в C# коде могут оказаться пустыми как произошло у меня.
Когда вы добавляете .AsSplitQuery(): var posts = context.Posts .Include(p => p.Comments) .Include(p => p.Tags) .AsSplitQuery() // <-- Разделяем запрос .ToList(); EF Core выполнит три отдельных, быстрых SQL-запроса:
-- С AsSplitQuery(): НЕСКОЛЬКО ПРОСТЫХ ЗАПРОСОВ
-- Запрос 1: Получить посты SELECT * FROM Posts;
-- Запрос 2: Получить комментарии для этих постов SELECT * FROM Comments WHERE PostId IN (...);
-- Запрос 3: Получить теги для этих постов SELECT * FROM Tags WHERE PostId IN (...);
Используйте AsSplitQuery() всегда, когда вы с помощью .Include() подгружаете больше одной коллекции (связь "один-ко-многим") в одном запросе.
Есть холивар насчет EF. Часто слышал , что он опасен вот подобными выкрутасами и поэтому в больших компаниях предпочитают Dapper. Но для старта он незаменим. Да и если его нормально готовить он и в серьезном проекте вполне хорошо работает. С таким я тоже сталкивался )))
В этом посте были ссылки, но мы их удалили по правилам Сетки