Книги онлайн и без регистрации » Разная литература » Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 300 301 302 303 304 305 306 307 308 ... 407
Перейти на страницу:
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();

    Assert.Equal(expectedCount, count);

}

Оба теста создают те же самые обращения SQL к серверу (в каждом тесте значение для MakeId изменяется на основе [InlineData]):

exec sp_executesql N'SELECT COUNT(*)

FROM [dbo].[Inventory] AS [i]

WHERE ([i].[IsDrivable] = CAST(1 AS bit)) AND ([i].[MakeId] = @__makeId_0)'

,N'@__makeId_0 int',@__makeId_0=6

Any() и All()

Методы Any() и All() проверяют набор записей, чтобы выяснить, соответствует ли критериям любая запись (Any()) или же все записи (Аll()). Как и вызовы методов агрегирования, их можно добавлять в конец запроса LINQ с вызовами Where() либо же помещать выражение фильтрации в сам вызов метода. Методы Any() и All() выполняются на серверной стороне, а из запроса возвращается булевское значение. Глобальные фильтры запросов оказывают воздействие на методы Any() и All(); их можно отключить с помощью IgnoreQueryFilters().

Все операторы SQL, показанные в этом разделе, были получены с применением профилировщика SQL Server. Первый тест (из CarTests.cs) проверяет, имеет ли любая запись Car специфическое значение MakeId:

[Theory]

[InlineData(1, true)]

[InlineData(11, false)]

public void ShouldCheckForAnyCarsWithMake(int makeId, bool expectedResult)

{

  var result = Context.Cars.Any(x => x.MakeId == makeId);

  Assert.Equal(expectedResult, result);

}

Для первого теста [Theory] выполняется следующий код SQL:

exec sp_executesql N'SELECT CASE

  WHEN EXISTS (

    SELECT 1

    FROM [dbo].[Inventory] AS [i]

    WHERE ([i].[IsDrivable] = CAST(1 AS bit))

      AND ([i].[MakeId] = @__makeId_0)) THEN

    CAST(1 AS bit)

   ELSE CAST(0 AS bit)

END',N'@__makeId_0 int',@__makeId_0=1

Второй тест проверяет, имеют ли все записи Car специфическое значение MakeId:

[Theory]

[InlineData(1, false)]

[InlineData(11, false)]

public void ShouldCheckForAllCarsWithMake(int makeId, bool expectedResult)

{

  var result = Context.Cars.All(x => x.MakeId == makeId);

  Assert.Equal(expectedResult, result);

}

Вот код SQL, выполняемый для второго теста [Theory]:

exec sp_executesql N'SELECT CASE

  WHEN NOT EXISTS (

    SELECT 1

    FROM [dbo].[Inventory] AS [i]

    WHERE ([i].[IsDrivable] = CAST(1 AS bit))

      AND ([i].[MakeId] <> @__makeId_0)) THEN

    CAST(1 AS bit)

  ELSE CAST(0 AS bit)

END',N'@__makeId_0 int',@__makeId_0=1

Получение данных из хранимых процедур

Последний шаблон извлечения данных, который необходимо изучить, предусматривает получение данных из хранимых процедур. Несмотря на некоторые пробелы EF Core в плане работы с хранимыми процедурами (по сравнению с EF 6), не забывайте, что инфраструктура EF Core построена поверх ADO.NET. Нужно просто спуститься на уровень ниже и вспомнить, как вызывались хранимые процедуры до появления инструментов объектно-реляционного отображения. Показанный далее метод в CarRepo создает обязательные параметры (входной и выходной), задействует свойство Database экземпляра ApplicationDbContext и вызывает ExecuteSqlRaw():

public string GetPetName(int id)

{

  var parameterId = new SqlParameter

    {

    ParameterName = "@carId",

    SqlDbType = System.Data.SqlDbType.Int,

    Value = id,

  };

  var parameterName = new SqlParameter

  {

    ParameterName = "@petName",

    SqlDbType = System.Data.SqlDbType.NVarChar,

    Size = 50,

    Direction = ParameterDirection.Output

  };

  var result = Context.Database

    .ExecuteSqlRaw("EXEC [dbo].[GetPetName] @carId, @petName OUTPUT",

                    parameterId, parameterName);

  return (string)parameterName.Value;

}

При наличии такого кода тест становится тривиальным. Добавьте в файл класса CarTests.cs следующий тест:

[Theory]

[InlineData(1, "Zippy")]

[InlineData(2, "Rusty")]

[InlineData(3, "Mel")]

[InlineData(4, "Clunker")]

[InlineData(5, "Bimmer")]

[InlineData(6, "Hank")]

[InlineData(7, "Pinky")]

[InlineData(8, "Pete")]

[InlineData(9, "Brownie")]

public void ShouldGetValueFromStoredProc(int id, string expectedName)

{

    Assert.Equal(expectedName, new CarRepo(Context).GetPetName(id));

}

Создание записей

Записи добавляются в базу данных за счет их создания в коде, добавления к DbSet<T> и вызова метода SaveChanges()/SaveChangesAsync() контекста. Во время выполнения метода SaveChanges() объект ChangeTracker сообщает обо всех добавленных сущностях, а инфраструктура EF Core вместе с поставщиком баз данных создают подходящий оператор (операторы) SQL для вставки записи (записей).

1 ... 300 301 302 303 304 305 306 307 308 ... 407
Перейти на страницу:

Комментарии
Минимальная длина комментария - 20 знаков. В коментария нецензурная лексика и оскорбления ЗАПРЕЩЕНЫ! Уважайте себя и других!
Комментариев еще нет. Хотите быть первым?