Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю
Тот же процесс применяется в случае использования метода
Reference()Выполнение низкоуровневых запросов SQL с помощью LINQ
Иногда получить корректный оператор LINQ для компилируемого запроса сложнее, чем просто написать код SQL напрямую. К счастью, инфраструктура EF Core располагает механизмом, позволяющим выполнять низкоуровневые операторы SQL в
DbSet<T>FromSqlRaw()FromSqlRawInterpolated()Если низкоуровневый оператор SQL не является завершающим (скажем, хранимой процедурой, пользовательской функцией или оператором, который использует общее табличное выражение или заканчивается точкой с запятой), тогда в запрос можно добавить дополнительные операторы LINQ. Дополнительные операторы LINQ наподобие конструкций
Include()OrderBy()Where()При использовании одного из вариантов
FromSql*()FromSqlRaw()FromSqlInterpolated()Предположим, что для сущности
CarInventoryId1Makevar car = Context.Cars .FromSqlInterpolated($"Select * from dbo.Inventory where Id = {carId}") .Include(x => x.MakeNavigation) .First();Механизм трансляции LINQ to SQL объединяет низкоуровневый оператор SQL с остальными операторами LINQ и выполняют следующий запрос:
SELECT TOP(1) [c].[Id], [c].[Color], [c].[IsDrivable], [c].[MakeId], [c].[PetName], [c].[TimeStamp], [m].[Id], [m].[Name], [m].[TimeStamp]FROM (Select * from dbo.Inventory where Id = 1) AS [c]INNER JOIN [dbo].[Makes] AS [m] ON [c].[MakeId] = [m].[Id]WHERE [c].[IsDrivable] = CAST(1 AS bit)Имейте в виду, что есть несколько правил, которые необходимо соблюдать в случае применения низкоуровневых запросов SQL с LINQ.
• Запрос SQL должен возвращать данные для всех свойств сущностного типа.
• Имена столбцов должны совпадать с именами свойств, с которыми они сопоставляются (улучшение по сравнению с версией EF 6, где сопоставления игнорировались).
• Запрос SQL не может содержать связанные данные.
Пакетирование операторов
В EF Core значительно повышена производительность при сохранении изменений в базе данных за счет выполнения операторов в одном и более пакетов. В итоге объем взаимодействия между приложением и базой данных уменьшается, увеличивая производительность и потенциально сокращая затраты (скажем, для облачных баз данных, где за транзакции приходится платить).
Исполняющая среда EF Core пакетирует операторы создания, обновления и удаления с использованием табличных параметров. Количество операторов, которые пакетирует EF Core, зависит от поставщика баз данных. Например, в SQL Server пакетарование неэффективно для менее 4 и более 40 операторов. Независимо от количества пакетов все операторы по- прежнему выполняются в рамках транзакции. Размер пакета можно конфигурировать посредством
DbContextOptionsЕсли бы вы вставляли четыре записи об автомобилях в одной транзакции, как показано ниже:
var cars = new List<Car>{ new Car { Color = "Yellow", MakeId = 1, PetName = "Herbie" }, new Car { Color = "White", MakeId = 2, PetName = "Mach 5" }, new Car { Color = "Pink", MakeId = 3, PetName = "Avon" }, new Car { Color = "Blue", MakeId = 4, PetName = "Blueberry" },};Context.Cars.AddRange(cars);Context.SaveChanges();то исполняющая среда EF Core пакетировала бы операторы в одиночное обращение.
Вот как выглядел бы сгенерированный запрос:
exec sp_executesql N'SET NOCOUNT ON;DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);MERGE [Dbo].[Inventory] USING (VALUES (@p0, @p1, @p2, 0),(@p3, @p4, @p5, 1),(@p6, @p7, @p8, 2),(@p9, @p10, @p11, 3)) AS i ([Color], [MakeId], [PetName], _Position) ON 1=0WHEN NOT MATCHED THENINSERT ([Color], [MakeId], [PetName])VALUES (i.[Color], i.[MakeId], i.[PetName])OUTPUT INSERTED.[Id], i._PositionINTO @inserted0;SELECT [t].[Id], [t].[IsDrivable], [t].[TimeStamp] FROM [Dbo].[Inventory] tINNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id])ORDER BY [i].[_Position];',N'@p0 nvarchar(50),@p1 int,@p2 nvarchar(50),@p3 nvarchar(50),@p4 int,@p5 nvarchar(50),@p6 nvarchar(50),@p7 int,@p8 nvarchar(50),