Чтобы убедиться, что прокси-серверы с отложенной загрузкой включены, необходимо объявить свойства как virtual
и убедиться, что отложенная загрузка не отключена в DbContext.
Поведение, которое вы, вероятно, видите, связано с dbContext уже выбрал одну из связанных сущностей и автоматически связал ее с запрашиваемой связанной сущностью.
Давайте рассмотрим пример с проектом (ID # 1) с клиентом (ID # 1)
Если вы сделаете что-то вроде:
using ( var context = new MyDbContext())
{
var project = context.Projects.Single(x => x.Id == 1);
Console.WriteLine("Has Client: " + (project.Client != null).ToString());
}
Без virtual
вы получите «Имеет клиента: Ложь». При virtual
этот оператор консоли будет запускать второй запрос к БД и затем возвращать «Имеет клиента: True».
Теперь, когда все становится интереснее:
using ( var context = new MyDbContext())
{
var tempClient = context.Clients.Single(x => x.Id == 1);
var project = context.Projects.Single(x => x.Id == 1);
Console.WriteLine("Has Client: " + (project.Client != null).ToString());
}
В этом случае наш контекст просто загружает ссылку на Client ID # 1. Мы больше ничего не делаем и не связываем это с нашей ссылкой на проект, мы просто загружаем проект так же, как и раньше. В этом случае вывод будет «Имеет клиента: Истина», даже если мы не хотим его загружать, и он не помечен как virtual
. Поскольку Проект № 1 имеет ссылку на Клиента № 1, а Клиент № 1 уже отслеживается DbContext, ссылка включается, когда мы запрашиваем Проект № 1.
Это является следствием использования долго работающих DbContexts, которые могут привести к довольно непредсказуемому поведению в приложениях, которые полностью ситуативны. Вы должны позаботиться о продолжительном, даже запросить ограниченные экземпляры DbContext, потому что это может привести к получению неполных изображений ваших данных. Например, если у вас есть родитель с дочерними ссылками, где у Родителя № 1 есть 3 дочерних элемента. (# 1, # 2 и # 3) Если ваш контекст по какой-либо причине загрузился и отслеживает дочерние элементы # 1 и # 2, и вы позже загружаете Parent # 1, не желая загружать дочерние элементы, коллекция Children этого родителя просто перечислит 2 из 3 детей (# 1 и # 2), которые могут дать вашему клиенту неполное и неточное представление данных. (Забавные ошибки, которые можно отследить, когда клиенты «иногда» видят неполные данные без видимой причины.)
В общем случае рекомендуется, чтобы все ссылки были помечены как virtual
и чтобы продолжительность жизни DbContext была как можно короче. Я рекомендую использовать шаблон единицы работы, который может быть введен и ограничен временем жизни запроса, но отвечает за создание более ограниченных областей действия для самих DbContexts, аналогично using (var context = new MyDbContext())
без привязки вашего кода к DbContext.