{
var carId = 1;
var car = Context.Cars
.FromSqlInterpolated($"Select * from dbo.Inventory where Id = {carId}")
.Include(x => x.MakeNavigation)
.First();
Assert.Equal("Black", car.Color);
Assert.Equal("VW", car.MakeNavigation.Name);
}
[Theory]
[InlineData(1, 1)]
[InlineData(2, 1)]
[InlineData(3, 1)]
[InlineData(4, 2)]
[InlineData(5, 3)]
[InlineData(6, 1)]
public void ShouldGetTheCarsByMakeUsingFromSql(int makeId, int expectedCount)
{
var entity = Context.Model.FindEntityType($"{typeof(Car).FullName}");
var tableName = entity.GetTableName();
var schemaName = entity.GetSchema();
var cars = Context.Cars.FromSqlRaw($"Select * from {schemaName}.{tableName}")
.Where(x => x.MakeId == makeId).ToList();
Assert.Equal(expectedCount, cars.Count);
}
Во время применения методов FromSqlRaw()/FromSqlInterpolated()
действует ряд правил: столбцы, возвращаемые из оператора SQL, должны соответствовать столбцам в модели, должны возвращаться все столбцы для модели, а возвращать связанные данные не допускается.
Методы агрегирования
В EF Core также поддерживаются методы агрегирования серверной стороны (Мах()
, Min()
, Count()
, Average()
и т.д.). Вызовы методов агрегирования можно добавлять в конец запроса LINQ с вызовами Where()
или же сам вызов метода агрегирования может содержать выражение фильтра (подобно First()
и Single()
). Агрегирование выполняется на серверной стороне и из запроса возвращается одиночное значение. Глобальные фильтры запросов оказывают воздействие на методы агрегирования и могут быть отключены с помощью IgnoreQueryFiltersсе()
. В операторы SQL, показанные в этом разделе, были получены с использованием профилировщика SQL Server.
Первый тест (из CarTests.cs
) просто подсчитывает все записи Car
в базе данных. Из-за того, что фильтр запросов активен, результатом подсчета будет 9:
[Fact]
public void ShouldGetTheCountOfCars()
{
var count = Context.Cars.Count();
Assert.Equal(9, count);
}
Ниже приведен код SQL, который выполнялся:
The executed SQL is shown here:SELECT COUNT(*)
FROM [dbo].[Inventory] AS [i]
WHERE [i].[IsDrivable] = CAST(1 AS bit)
После добавления вызова IgnoreQueryFilters()
метод Count()
возвращает 10 и конструкция WHERE
удаляется из запроса SQL:
[Fact]
public void ShouldGetTheCountOfCarsIgnoreQueryFilters()
{
var count = Context.Cars.IgnoreQueryFilters().Count();
Assert.Equal(10, count);
}
Вот сгенерированный код SQL:
SELECT COUNT(*) FROM [dbo].[Inventory] AS [i]
Следующие тесты (из CarTests.cs
) демонстрируют метод Count()
с условием WHERE
. В первом тесте выражение добавляется прямо в вызов метода Count()
, а во втором вызов метода Count()
помещается в конец запроса LINQ:
[Theory]
[InlineData(1, 1)]
[InlineData(2, 1)]
[InlineData(3, 1)]
[InlineData(4, 2)]
[InlineData(5, 3)]
[InlineData(6, 1)]
public void ShouldGetTheCountOfCarsByMakeP1(int makeId, int expectedCount)
{
var count = Context.Cars.Count(x=>x.MakeId == makeId);
Assert.Equal(expectedCount, count);
}
[Theory]
[InlineData(1, 1)]
[InlineData(2, 1)]
[InlineData(3, 1)]
[InlineData(4, 2)]
[InlineData(5, 3)]
[InlineData(6, 1)]
public void ShouldGetTheCountOfCarsByMakeP2(int makeId, int expectedCount)
{
var count = Context.Cars.Where(x => x.MakeId == makeId).Count();