Поскольку вы говорите, что у вас есть лениво загруженная коллекция Chapters
в вашем классе Story
, я предполагаю, что Chapters
на самом деле является коллекцией динамических прокси-объектов.Если вы посмотрите, что происходит в базе данных с помощью профилировщика, вы увидите, что эта строка ...
var chapters = story.Chapters.Select(
ch => new ChapterDisplayViewModel {
Id = ch.Id,
Number = ch.Number});
... выполняет запрос в базе данных, который запрашивает все Chapter
объекты (проекция на ChapterDisplayViewModel
не происходит в базе данных).И это единственный запрос к базе данных.Следующее ...
if (chapters.Any(c => c.Number == chapterNum))
chapters.Where(c => c.Number == chapterNum).Single().IsSelected = true;
... выполняется в памяти уже загруженной коллекции Chapters
.Проекция происходит в этой точке.
Но это означает, что оператор Single
материализует объект ChapterDisplayViewModel
, это означает: где-то внутри new ChapterDisplayViewModel
происходит.Простая проверка:
var viewModel1 = chapters.Where(c => c.Number == chapterNum).Single();
var viewModel2 = chapters.Where(c => c.Number == chapterNum).Single();
bool sameObjects = object.ReferenceEquals(viewModel1, viewModel2);
sameObjects
- это false
, что означает, что Single
не просто возвращает ссылки на объекты ViewModel, которые уже находятся в памяти, но создает их новые экземпляры.
Когда вы применяете ToList
в первом запросе, ViewModels сразу материализуются в коллекцию ViewModels в памяти, и Single
просто возвращает ссылку на соответствующий, но уже существующий объект.sameObjects
будет true
.
Итак, без ToList
вы устанавливаете свойство IsSelected
для только что материализованного объекта, на который вы больше не ссылаетесь, и поэтому сразу же исчезают в сборщике мусора.С ToList
вы устанавливаете свойство для уникального объекта внутри коллекции в памяти.Когда вы используете эту коллекцию по вашему мнению, флаг все еще там.