Я мог бы воспроизвести именно то поведение, которое вы описываете.Я получил работу так:
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Include(c => c.Students)
.Where(c => c.Id == 1)
.Load();
Я не знаю, почему мы должны быть вынуждены загрузить другую сторону отношения «многие ко многим» (Include(...)
), когда мы хотим толькозагрузить одну коллекцию.Для меня это действительно похоже на ошибку, если я не пропустил какую-то скрытую причину этого требования, которое где-то задокументировано или нет.
Редактировать
Другой результат: Ваш оригинальный запрос (без включения) ...
context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.Load();
... фактически загружает курсы в DbContext
как ...
var localCollection = context.Courses.Local;
... шоу.Курс с идентификатором 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
.И я думаю, что ответ таков: из-за Spansion Span .
Relationship Span - это функция в EF, которая автоматически фиксирует отношения между объектами, которые находятся в контексте или которые только что загружены в контекст,Но это не происходит для всех типов отношений.Это происходит, только если кратность равна 0 или 1 на одном конце.
В нашем примере это означает: когда мы загружаем Presentations
в контекст (по нашему отфильтрованному явному запросу), EF также загружает внешний ключиз Presentation
переходит к сущности Student
- «прозрачно», что означает, независимо от того, выставлен ли FK как свойство в модели not.Этот загруженный FK позволяет EF распознавать, что загруженный Presentations
принадлежит объекту Student
, который уже находится в контексте.
Но это не относится к коллекции Courses
.Курс не имеет внешнего ключа к сущности Student
.Между ними есть таблица соединений «многие ко многим».Таким образом, при загрузке Courses
EF не распознает, что эти курсы принадлежат Student
, который находится в контексте, и, следовательно, не фиксирует коллекцию навигации в сущности Student
.
EF выполняет это автоматическое исправление только для ссылок (но не для коллекций) по соображениям производительности:
Чтобы исправить связь, EF прозрачно переписывает запрос, чтобы получить информацию об отношениях для всех отношений, кратность которых равна 0..1 или 1на другом конце;другими словами, свойства навигации, которые являются ссылкой на сущность.Если у сущности есть отношение с кратностью, большей 1, EF не будет возвращать информацию о связи, потому что это может повлиять на производительность и по сравнению с переносом одного иностранца вместе с остальной частью записи.Получение информации о взаимоотношениях означает получение всех внешних ключей, которые есть в записях.
Цитата со страницы 128 из Подробное руководство Зеешана Хирани по EF .
Он основан на EF 4 и ObjectContext, но я думаю, что он все еще действителен в EF 4.1, поскольку DbContext в основном является оболочкой для ObjectContext.
К сожалению, при использовании Load
.
необходимо учитывать довольно сложные вещи.
И еще один Правка
Итак, что мы можем сделать, когда мы хотим явно загрузить одну отфильтрованную сторону отношения «многие ко многим»? Возможно только это:
student.Courses = context.Entry(student)
.Collection(s => s.Courses)
.Query()
.Where(c => c.Id == 1)
.ToList();