Вспомните, что при использовании LINQ для запрашивания из базы данных списка сущностей запрос не выполняется до тех пор, пока не начнется проход по результатам запроса, пока запрос не будет преобразован в List
(или объект) либо же пока не произойдет привязка запроса к списковому элементу управления (вроде сетки данных). Запрос единственной записи выполняется немедленно в случае применения вызова First()
, Single()
и т.д.
Нововведением версии EF Core 5 стало то, что в большинстве запросов LINQ можно вызывать метод ToQueryString()
для исследования запроса, который выполняется в отношении базы данных. Для разделяемых запросов метод ToQueryString()
возвращает только первый запрос, который будет выполняться. В рассматриваемых далее тестах это значение по возможности присваивается переменной (qs
), чтобы вы могли изучить запрос во время отладки тестов.
Первый набор тестов (если только специально не указано иначе) находится в файле класса CustomerTests.cs
.
Получение всех записей
Чтобы получить все записи из таблицы, просто используйте свойство DbSet
на прямую без каких-либо операторов LINQ. Добавьте приведенный ниже тест [Fact]
:
[Fact]
public void ShouldGetAllOfTheCustomers()
{
var qs = Context.Customers.ToQueryString();
var customers = Context.Customers.ToList();
Assert.Equal(5, customers.Count);
}
Выделенный полужирным оператор транслируется в следующий код SQL:
SELECT [c].[Id], [c].[TimeStamp], [c].[FirstName], [c].[FullName],
[c].[LastName]
FROM [Dbo].[Customers] AS [c]
Тот же самый процесс применяется для сущностей без ключей, подобных модели представления CustomerOrderViewModel
, которая сконфигурирован на получение своих данных из представления CustomerOrderView
:
modelBuilder.Entity
.ToView("CustomerOrderView", "dbo");
Экземпляр DbSet
для моделей представлений предлагает всю мощь запросов DbSet
для сущности с ключом. Отличие касается возможностей обновления. Изменения модели представления не могут быть сохранены в базе данных, тогда как изменения сущностей с ключами — могут. Добавьте в файл класса OrderTest.cs
показанный далее тест, чтобы продемонстрировать получение данных из представления:
public void ShouldGetAllViewModels()
{
var qs = Context.Orders.ToQueryString();
var orders = Context.Orders.ToList();
Assert.NotEmpty(orders);
Assert.Equal(5,orders.Count);
}
Выделенный полужирным оператор транслируется в следующий код SQL:
SELECT [c].[Color], [c].[FirstName], [c].[IsDrivable], [c].[LastName],
[c].[Make], [c].
[PetName]
FROM [dbo].[CustomerOrderView] AS [c]
Фильтрация записей
Метод Where()
используется для фильтрации записей из DbSet
. Несколько вызовов Where()
можно плавно объединять в цепочку для динамического построения запроса. Выстроенные в цепочку вызовы Where()
всегда объединяются с помощью операции "И". Для объединения условий с применением операции "ИЛИ" необходимо использовать один вызов Where()
.
Приведенный ниже тест возвращает заказчиков с фамилией, начинающейся с буквы "W" (нечувствительно к регистру символов):
[Fact]
public void ShouldGetCustomersWithLastNameW()
{
IQueryable
.Where(x => x.PersonalInformation.LastName.StartsWith("W"));
var qs = query.ToQueryString();
List
Assert.Equal(2, customers.Count);
}
Запрос LINQ транслируется в следующий код SQL:
SELECT [c].[Id], [c].[TimeStamp], [c].[FirstName], [c].[FullName],
[c].[LastName]
FROM [Dbo].[Customers] AS [c]
WHERE [c].[LastName] IS NOT NULL AND ([c].[LastName] LIKE N'W%')
Показанный далее тест возвращает заказчиков с фамилией, начинающейся с буквы "W" (нечувствительно к регистру символов), и именем, начинающимся с буквы "М" (нечувствительно к регистру символов), а также демонстрирует объединение вызовов Where()
в цепочку в запросе LINQ:
[Fact]