Правильно ли я понимаю IsLoaded? - PullRequest
2 голосов
/ 16 декабря 2011

Вот код вместе с моими предположениями, основанными на игре в LINQPad. Кто-нибудь может подтвердить, что так работает ленивая загрузка, и, возможно, предоставить какие-либо дополнительные сведения / ссылки, чтобы я мог понять, как это работает на серверной части? Заранее спасибо!

// Step 1.
var record = context.MyTable.First();

// Step 2.
var foreignKey = ForeignKeyTable.Where(x => x.Id == record.ForeignKeyId).Single();

// Step 3.
var entry = context.Entry(record);

// Step 4.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Step 5.
trace(record.ForeignKey.SomeProperty);
  1. Получить некоторую запись (запрашивается БД).
  2. Извлечение записи, которая оказывается свойством внешнего ключа record, без использования отложенной загрузки, например record.ForeignKey, для ее извлечения (запрашивается БД).
  3. Получите подробную информацию о сущности record.
  4. Это та часть, в которой я не уверен. В моем тестировании это выводит true. Я предполагаю, что IsLoaded не знает, имеет ли record.ForeignKey значение в данный момент, но знает, что record.ForeignKey уже отслеживается в контексте, основываясь на его знании record.ForeignKeyId и установленных отношениях.
  5. Кажется, что БД здесь не попал, и я предполагаю, что по той же причине IsLoaded возвращает true в 4. Он знает, что уже отслеживает объект foreignKey, поэтому он знает, что не имеет сделать ленивую загрузку.

Редактировать : Фактическая проблема, которую я пытаюсь решить, может быть проиллюстрирована так:

var record = context.MyTable.First();

var foreignKey = new ForeignKey() { Id = record.ForeignKeyId, SomeProperty = 5 };
context.ForeignKeyTable.Attach(foreignKey);

var entry = context.Entry(record);

// Returns false.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Doesn't query for ForeignKey, so it must know it's `loaded` somehow, and
// gets SomeProperty from my new foreignKey object. What???
trace(record.ForeignKey.SomeProperty);

Ответы [ 2 ]

2 голосов
/ 16 декабря 2011

EF исправляет отношения (свойства навигации) автоматически в соответствии со значениями первичного ключа и внешнего ключа при загрузке объекта из базы данных или при его присоединении к контексту.

В обоих фрагментах кода вы загрузили record, который имеет внешний ключ для вашего ForeignKeyTable. Контекст знает это значение. (Между прочим, не имеет значения, если вы выставили внешний ключ в вашей модели. Он всегда будет загружаться, также без свойства FK в вашей модели. Это можно увидеть, наблюдая за запросом SQL.)

В обоих случаях вы потом присоединяете сущность ForeignKey к контексту, который имеет в качестве первичного ключа значение record.ForeignKeyId, о котором контекст уже знает. Как следствие, EF установит свойство навигации record.ForeignKey для этой присоединенной ForeignKey сущности.

Очевидно, IsLoaded не сообщает вам, присоединена ли сущность к контексту, потому что в обоих примерах она присоединена, но один возвращает true, а другой false. Это также не говорит вам, относится ли record.ForeignKeyId к сущности, потому что это также имеет место в обоих примерах.

Это говорит вам, очевидно, только о том, что сущность действительно была загружена из базы данных (и не только присоединена вручную) (что также Intellisense говорит о IsLoaded). Это единственная разница между вашим первым и вторым примером.

И кажется, что отложенная загрузка контролируется не только флагом IsLoaded. Если вы присоединяете объект для свойства навигации к контексту, отложенная загрузка больше не происходит, хотя IsLoaded равно false.

Что произойдет, если ваша последняя строка во втором фрагменте кода фактически вызовет отложенную загрузку? Загружаемый объект ForeignKey должен иметь тот же ключ, что и объект ForeignKey, который вы уже прикрепили (поскольку record имеет это значение как свойство FK ForeignKeyId). Но поскольку никакие два объекта с одинаковым ключом не могут быть присоединены к контексту, это должен быть один и тот же объект. Но тогда нет необходимости загружать его, так как такой объект уже находится в памяти и подключен.

1 голос
/ 16 декабря 2011
// Step 1.
var record = context.MyTable.First();

// Step 2.
var foreignKey = ForeignKeyTable.Where(x => x.Id == record.ForeignKeyId).Single();

// Step 3.
var entry = context.Entry(record);

// Step 4.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Step 5.
trace(record.ForeignKey.SomeProperty);
  1. Получить некоторую запись (запрашивается БД). да, и результирующая запись присоединяется к DbContext.
  2. Извлечение записи, которая оказывается свойством внешнего ключа записи, без использования отложенной загрузки, такой как record.ForeignKey, для ее извлечения (DBзапрашивается). да.Если бы вы хотели загрузить внешний ключ в # 1, вы бы использовали context.MyTable.Include (m => m.ForeignKey) .First ();Это привело бы к извлечению записи вместе с fk в 1 запросе.
  3. Получение сведений о записи объекта. Вроде ... это детали сущности относительно DbContext (что прикреплено / удалено / загружено / и т.д.)
  4. Это часть, в которой я не уверен.В моем тестировании это выводит true.Я предполагаю, что IsLoaded не знает, имеет ли значение record.ForeignKey в настоящее время, но знает, что record.ForeignKey уже отслеживается в контексте на основе его знания record.ForeignKeyId и установленных отношений. Это означает, что DbContext не нужно запускать другой запрос для загрузки данных для внешнего ключа.Если вы выполняете record.ForeignKey, данные уже есть, и дополнительная поездка в базу данных не требуется .
  5. Кажется, что база данных не нажата, и я предполагаю, что она для того жепричина IsLoaded возвращает true в 4. Он знает, что он уже отслеживает объект foreignKey, поэтому он знает, что не должен выполнять ленивую загрузку. Права уже были загружены на шаге №2, поэтому для получения его из базы данных не потребовалось никаких дополнительных поездок.

Обновление после редактирования вопроса

Согласно EF, метод .Attach для IDbSet:

Присоединяет данную сущность к контексту, лежащему в основе набора.Таким образом, объект помещается в контекст в неизмененном состоянии, как если бы он был прочитан из базы данных.

...