Свойство навигации загружено не полностью после активной загрузки

1

Я использую код, похожий на этот, чтобы выбрать большой список объектов, для цели только для чтения:

using (DBContext db = new MyContextClass())
{
    ... data creation ... 
    db.SaveChanges();
}

using (DBContext db = new MyContextClass())
{
     db.Configuration.LazyLoadingEnabled = false;
     db.Configuration.ProxyCreationEnabled = false;
     db.Configuration.AutoDetectChangesEnabled = false;

     DbQuery data = db.Set(someType)
     foreach (string propertyName op in somePropertieNames)
                data = data.Include(propertyName);

     foreach (object item in data.AsNoTracking())
         ScanNavigatorsOf(item);
}

в ScanNavigatorsOf() я прочитал все свойства навигации, и я заметил, что первый объект, полученный в цикле foreach имеет неполные коллекции и ссылки. Кажется, что совокупность свойств навигации не завершена в момент, когда программа попадает на мой ScanNavigatorsOf(...). Все остальные объекты имеют полные свойства навигации. Я запускаю модульные тесты, поэтому я могу гарантировать, что объекты хорошо хранятся в базе данных.

Как можно дождаться полного заполнения навигационных коллекций и ссылок загруженных объектов?

Как описано в ObjectContext.ObjectMaterialized Event, коллекции, кажется, не материализуются одновременно с основным объектом, но как узнать, когда процесс будет выполнен?

Теги:
entity-framework
entity-framework-6

2 ответа

0

Сначала загрузите все данные с помощью ToList() затем сканируйте свойства навигации:

var queryableData = db.Set(someType).AsNoTracking();
var data = somePropertieNames.Aggregate(queryableData , (current, property) => current.Include(property)).ToList();
foreach (object item in data)
         ScanNavigatorsOf(item);
0

Я уверен, что вы испытываете побочные эффекты отключения DetectChanges. Это вызов EF делает много раз ниже поверхности, чтобы гарантировать, что все ассоциации между отслеживаемыми объектами были установлены правильно и совпадают с примитивными значениями внешнего ключа (это называется фиксацией отношений). Может быть, причина для вас отключить его, но, как говорит Лерман и Миллер в своей книге DbContext:

Разработка, когда DetectChanges нужно вызывать, не так тривиальна, как может показаться. Команда Entity Framework настоятельно рекомендует вам только заменять вручную вызов DetectChanges, если у вас возникают проблемы с производительностью. Также рекомендуется отключить автоматическое определение DetectChanges для плохо выполняемых разделов кода и повторно использовать его после завершения этого раздела.

Кроме того, вы получаете объекты без отслеживания. Теперь EF почти полностью искалечен, когда дело касается ассоциаций.

Вы должны либо позволить DetectChanges выполнять свою работу, либо называть ее в цикле. И включить отслеживание, иначе нет ничего, что может сделать трекер изменений, чтобы исправить ассоциации.

 foreach (object item in data)
 {
     db.ChangeTracker.DetectChanges();
     ScanNavigatorsOf(item);
 }

Или включите AutoDetectChangesEnabled прежде чем цикл будет запущен, когда в ScanNavigatorsOf один из этих методов запускает DetectChanges.

Но в AsNoTracking есть еще одна AsNoTracking. Эффект отключения отслеживания изменений заключается в том, что контекст не может служить идентификационной картой, а это означает: он не может гарантировать, что каждая запись в базе данных будет реализована ровно один раз.

Если есть 1-n-1 объединение в вашем Includes, скажу Order-OrderLine-Product, без отслеживания для каждого OrderLine нового Product экземпляр будет создан, даже если " тот же самый" продукт был уже создан для предыдущей строки заказа. Это не большая проблема, если вы используете данные только для чтения, но как только вы собираетесь присоединить их к контексту (например, для репликации), вы столкнетесь с дублирующими ключевыми исключениями.

Короче говоря, когда важны ассоциации, пусть трекер изменений выполняет свою работу и убеждается, что DetectChanges вызван вовремя.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню