Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

3 года назад
Открыть в
День 1539. #ЗаметкиНаПолях Чистые SQL-запросы в EF Core В EF7 появилась поддержка возврата скалярных типов с помощью SQL-запросов. В EF8 появилась поддержка запросов несопоставленных (unmapped) типов с помощью чистого SQL. Это то, что Dapper предлагает по умолчанию, и приятно видеть, что EF Core догоняет его. EF Core и SQL В EF8 чистые SQL-запросы могут возвращать любой тип без необходимости включать его в модель EF. Вы можете запрашивать несопоставленные типы с помощью методов SqlQuery и SqlQueryRaw. Метод SqlQuery использует интерполяцию строк для параметризации запроса, защищая от атак SQL-инъекцией. Вот пример запроса, возвращающего список OrderSummary:
var start = new DateOnly(2023, 1, 1);
var orders = await dbContext
  .Database
  .SqlQuery<Order>(
   @$"SELECT * FROM Orders 
      AS o WHERE o.Created >= {start}")
  .ToListAsync();

В БД будет отправлен следующий запрос:
SELECT * FROM Orders AS o WHERE o.Created >= @p0

Тип, используемый для результата запроса, может иметь параметризованный конструктор. Имена свойств не обязательно должны совпадать с именами столбцов в базе данных, но они должны совпадать с именами полей в результирующем наборе. Вы также можете выполнять чистые SQL-запросы к представлениям, функциям и хранимым процедурам. SQL + LINQ Интересной особенностью SqlQuery является то, что он возвращает IQueryable, который можно дополнить с помощью LINQ. Можно добавить оператор Where после вызова SqlQuery:
var orders = await dbContext
  .Database
  .SqlQuery<Order>(
    "SELECT * FROM Orders AS o")
  .Where(o => o.Created >= start)
  .ToListAsync();
Однако, в результате получится неоптимальный запрос:
SELECT s.Id, s.CustomerId, s.Price, s.Created
FROM (
  SELECT * FROM Orders AS o
) AS s
WHERE s.Created >= @p0

Также возможно добавить OrderBy, Skip и Take:
var orders = await dbContext
  .Database
  .SqlQuery<Order>(
    @$"SELECT * FROM Orders AS o 
      WHERE o.Created >= {start}")
    .OrderBy(o => o.Id)
    .Skip(10)
    .Take(5)
    .ToListAsync();

Получим следующий запрос:
SELECT s.Id, s.CustomerId, s.Price, s.Created
FROM (
  SELECT * FROM Orders AS o WHERE o.Created >= @p0
) AS s
ORDER BY s.Id
OFFSET @p1 ROWS FETCH NEXT @p2 ROWS ONLY

Производительность аналогична LINQ-запросам с проекцией с помощью Select. SQL-запросы для модификации данных Если вы хотите изменить данные в базе данных с помощью SQL, вы обычно пишете запрос, который не возвращает результата. Запрос может быть UPDATE, DELETE или вызовом хранимой процедуры. Для этого можно использовать метод ExecuteSql:
dbContext.Database.ExecuteSql(
  @$"UPDATE Orders SET Status = 5 
     WHERE Created >= {start}");

ExecuteSql также защищает от SQL-инъекций путем параметризации аргументов, как и SqlQuery. В EF7 можно написать приведённый выше запрос с помощью LINQ и метода ExecuteUpdate. Также есть метод ExecuteDelete для удаления записей. Источник: https://www.milanjovanovic.tech/blog/ef-core-raw-sql-queries