Пишут ли запросы вручную при работе с Entity Framework?
Что проверяют
Понимаете ли вы, что LINQ это генератор SQL, а не замена ему, умеете ли смотреть на сгенерированный запрос и знаете ли безопасный способ выполнить свой. Ответ «EF всё делает сам» и ответ «всегда пишу SQL руками» одинаково слабые.
Как отвечать
По умолчанию LINQ, сырой SQL точечно: когда провайдер даёт заведомо плохой план, когда нужна возможность СУБД без поддержки в EF (оконные конструкции, MERGE, хинты, полнотекстовый поиск), когда массовая операция не должна тянуть сущности в память.
Назовите актуальный набор EF Core: FromSql и FromSqlInterpolated для запросов, возвращающих сущности, SqlQuery для скалярных и произвольных типов, ExecuteSql для команд без результата, ExecuteUpdate и ExecuteDelete для массовых изменений одним запросом. Старые Database.SqlQuery<T> и ExecuteSqlCommand это API из EF 6, выдавать их за текущие не стоит.
Безопасность отдельным пунктом: значения передаются параметрами. FromSqlInterpolated выглядит обычной интерполяцией, но подставляет параметры, а не текст, тогда как FromSqlRaw со склеенной строкой это инъекция.
Сильная часть ответа это порядок действий до сырого SQL: включить логирование (LogTo), посмотреть фактический запрос и план, проверить типовые причины. Чаще виноват не LINQ: N+1 от ленивой загрузки, декартов взрыв от нескольких Include без AsSplitQuery, отсутствие AsNoTracking на чтениях, вычисления, уехавшие на клиента, несовпадение типа параметра и колонки, из-за которого индекс не используется.
Где спотыкаются
Отвечают терминами EF 6 и теряются, когда просят сделать массовое обновление в EF Core: предлагают загрузить сущности и сохранить по одной вместо одного ExecuteUpdate.
Второе: собирают запрос конкатенацией, считая, что внутренний админский экран инъекции не подвержен. Подвержен, и первым это обнаружит не злоумышленник, а апостроф в фамилии.
Третье: уходят в сырой SQL, не посмотрев сгенерированный. Переписанный вручную запрос убирает симптом на одном экране, а причина (нет индекса, N+1, лишние Include) остаётся и всплывает на следующем.