Если связанные данные нужно загрузить сразу после того, как главная сущность была запрошена в память, то связанные сущности можно извлечь из базы данных с помощью последующих обращений к базе данных. Это запускается с применением метода Entry()
класса, производного от DbContext
. При загрузке сущностей на стороне "многие" отношения "один ко многим" используйте вызов метода Collection()
на результате Entry()
. Чтобы загрузить сущности на стороне "один" отношения "один ко многим" (или отношения "один к одному"), применяйте метод Reference()
. Вызов метода Query()
на результате Collection()
или Reference()
возвращает экземпляр реализации IQueryable
, который можно использовать для получения строки запроса (как видно в приводимых далее тестах) и для управления фильтрами запросов (как показано в следующем разделе). Чтобы выполнить запрос и загрузить запись (записи), вызовите метод Load()
на результате метода Collection()
, Reference()
или Query()
. Выполнение запроса начнется немедленно после вызова Load()
.
Представленный ниже тест (из CarTests.cs
) демонстрирует, каким образом загрузить связанные данные через навигационное свойство типа ссылки внутри сущности Car
:
[Fact]
public void ShouldGetReferenceRelatedInformationExplicitly()
{
var car = Context.Cars.First(x => x.Id == 1);
Assert.Null(car.MakeNavigation);
var query = Context.Entry(car).Reference(c => c.MakeNavigation).Query();
var qs = query.ToQueryString();
query.Load();
Assert.NotNull(car.MakeNavigation);
}
Вот сгенерированный код SQL:
DECLARE @__p_0 int = 1;
SELECT [m].[Id], [m].[Name], [m].[TimeStamp]
FROM [dbo].[Makes] AS [m]
WHERE [m].[Id] = @__p_0
В следующем тесте показано, как загрузить связанные данные через навигационное свойство типа коллекции внутри сущности Car
:
[Fact]
public void ShouldGetCollectionRelatedInformationExplicitly()
{
var car = Context.Cars.First(x => x.Id == 1);
Assert.Empty(car.Orders);
var query = Context.Entry(car).Collection(c => c.Orders).Query();
var qs = query.ToQueryString();
query.Load();
Assert.Single(car.Orders);
}
Сгенерированный код SQL выглядит так:
DECLARE @__p_0 int = 1;
SELECT [o].[Id], [o].[CarId], [o].[CustomerId], [o].[TimeStamp]
FROM [Dbo].[Orders] AS [o]
INNER JOIN (
SELECT [i].[Id], [i].[IsDrivable]
FROM [dbo].[Inventory] AS [i]
WHERE [i].[IsDrivable] = CAST(1 AS bit)
) AS [t] ON [o].[CarId] = [t].[Id]
WHERE ([t].[IsDrivable] = CAST(1 AS bit)) AND ([o].[CarId] = @__p_0)
Явная загрузка связанных данных с фильтрами запросов
Глобальные фильтры запросов активны не только при формировании запросов, генерируемых для энергичной загрузки связанных данных, но и при явной загрузке связанных данных. Добавьте (в MakeTests.cs
) приведенный далее тест:
[Theory]
[InlineData(1,1)]
[InlineData(2,1)]
[InlineData(3,1)]
[InlineData(4,2)]
[InlineData(5,3)]
[InlineData(6,1)]
public void ShouldGetAllCarsForAMakeExplicitlyWithQueryFilters(
int makeId, int carCount)
{
var make = Context.Makes.First(x => x.Id == makeId);
IQueryable
var qs = query.ToQueryString();
query.Load();
Assert.Equal(carCount,make.Cars.Count());
}