Ответ 1
Я мог бы воспроизвести именно то поведение, которое вы описываете. То, что я получил, это:
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Include(c => c.Students)
.Where(c => c.Id == 1)
.Load();
Я не знаю, почему мы должны быть вынуждены также загружать другую сторону отношения "многие ко многим" (Include(...)
), когда мы хотим загрузить только одну коллекцию. Для меня это действительно похоже на ошибку, если я не пропустил скрытую причину этого требования, которое где-то зарегистрировано или нет.
Edit
Другой результат: ваш исходный запрос (без включения)...
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.Load();
... фактически загружает курсы в DbContext
как...
var localCollection = context.Courses.Local;
... показывает. Курс с Id 1 действительно находится в этой коллекции, что означает: загружается в контекст. Но это не в дочерней коллекции студенческого объекта.
Изменить 2
Возможно, это не ошибка.
Прежде всего: мы используем здесь две разные версии Load
:
DbCollectionEntry<TEntity, TElement>.Load()
Intellisense говорит:
Загружает коллекцию объектов из базы данных. Обратите внимание, что объекты, которые уже существуют в контексте, не перезаписаны значениями из базы данных.
Для другой версии (метод расширения IQueryable
)...
DbExtensions.Load(this IQueryable source);
... Intellisense говорит:
Перечисляет запрос так, что для серверные запросы, такие как запросы System.Data.Entity.DbSet, System.Data.Objects.ObjectSet, System.Data.Objects.ObjectQuery, и другие результаты запроса будут загружены в связанные System.Data.Entity.DbContext, System.Data.Objects.ObjectContext или другой кэш на клиенте. Это эквивалентно вызову ToList, а затем отбросив список без накладные расходы на список.
Итак, в этой версии не гарантируется, что дочерняя коллекция заполняется, только чтобы объекты загружались в контекст.
Остается вопрос: зачем получает коллекцию Presentations
, а не коллекцию Courses
. И я думаю, что ответ таков: из-за Отношения > .
Сектор отношений - это функция в EF, которая автоматически фиксирует отношения между объектами, которые находятся в контексте или которые просто загружаются в контекст. Но это не происходит для всех типов отношений. Это происходит, только если кратность 0 или 1 на одном конце.
В нашем примере это означает: когда мы загружаем Presentations
в контекст (по нашему отфильтрованному явному запросу), EF также загружает внешний ключ Presentation
entites в объект Student
- "прозрачно", что означает, что независимо от того, будет ли FK выставлен как свойство в модели нет. Этот загруженный FK позволяет EF распознавать, что загруженный Presentations
принадлежит сущности Student
, которая уже находится в контексте.
Но это не так для коллекции Courses
. Курс не имеет внешнего ключа для объекта Student
. Между ними есть много-много-соединительная таблица. Таким образом, при загрузке Courses
EF не распознает, что эти курсы принадлежат Student
, который находится в контексте, и поэтому не фиксирует коллекцию навигации в объекте Student
.
EF делает это автоматическое исправление только для ссылок (а не коллекций) по соображениям производительности:
Чтобы зафиксировать взаимосвязь, EF прозрачно переписывает запрос, чтобы информация о взаимоотношениях для всех отношений который имеет кратность 0..1 or1 on другой конец; другими словами свойства навигации, которые являются сущностью Справка. Если предприятие имеет отношения с множественностью больше 1, EF не вернет информация о взаимоотношениях, поскольку она может быть удачным по производительности и по сравнению с привлечение одного иностранца вместе с остальная часть записи. приведение информация о взаимоотношениях означает получение всех внешние ключи, которые были записаны.
Цитата со страницы 128 Zeeshan Hirani в подробном руководстве к EF.
Он основан на EF 4 и ObjectContext, но я думаю, что это все еще действует в EF 4.1, поскольку DbContext в основном представляет собой оболочку вокруг ObjectContext.
К сожалению, довольно сложный материал, который следует учитывать при использовании Load
.
И еще один Edit
Итак, что мы можем сделать, когда хотим явно загрузить одну отфильтрованную сторону отношения "многие ко многим"? Возможно, только это:
student.Courses = context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.ToList();