Dynami c прокси / отложенная загрузка для сущностей не работает все время в ef6 - PullRequest
2 голосов
/ 14 января 2020

Я использую EF6 с моим веб-приложением и просто пытаюсь пролить свет на то, как именно работает загрузка / отложенная загрузка. Из моего исследования кажется, что если я хочу иметь динамические прокси c, мне нужно пометить свойства как «виртуальные». Также, похоже, что Dynami c прокси включены по умолчанию. Я не отключил отложенную загрузку или динамическую загрузку прокси c в моем контексте БД. У меня есть пример:

//action method which is passed in a projectId
var project = dbContext.Projects.SingleOrDefault(p => p.Id == projectId);
//inspect project by setting debug point here.


public class Project{
public Client Client{get;set;} // this has a dynamic proxy created when loading
public System System{get;set;} // this property is  just null
}

Обычно я должен обойти это, перейдя:

dbContext.Projects.Include(p => p.System).SingleOrDefault(p => p.Id == projectId);

Что дает? Может кто-нибудь объяснить мне это?

Ответы [ 2 ]

1 голос
/ 16 января 2020

Чтобы убедиться, что прокси-серверы с отложенной загрузкой включены, необходимо объявить свойства как 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.

0 голосов
/ 14 января 2020

Согласно этого руководства , создаются прокси-серверы Dynami c, если:

  • Класс POCO объявлен с доступом publi c.
  • Класс POCO не запечатан.
  • Класс POCO не является абстрактным.
  • Каждое свойство навигации объявлено как publi c, виртуальное.
  • Каждое свойство коллекции имеет тип ICollection <T>.
  • В контекстном классе включена опция ProxyCreationEnabled.

Все ли эти условия выполнены для вашего System класса?

...