Есть несколько вещей, которые нужно запомнить:
- Выполнение
From p in ctx.Products _
будет всегда выбирать из базы данных.
- LINQ ленив. Он не выполнит выбор базы данных, пока вы не выполните итерацию, а если вы выполните итерацию дважды, это сделает выбор базы данных дважды.
- Как данные, считанные из базы данных, объединяются с данными, уже находящимися в
ObjectContext
, зависит от MergeOption
запроса, который вы выполняете. Но это всегда будет происходить после выполнения SQL.
С учетом этих идей давайте рассмотрим ваш код:
Этот бит (1) создает IQueryable<Product>
, который можно использовать в качестве основы для итерации или определения других запросов. Обратите внимание, что на самом деле он не выполняет запрос к базе данных.
Dim oProducts = From p in ctx.Products _ // (1)
Where p.Active = True _
Select p
Следующий бит (2) выполняет итерацию IQueryable, определенную выше.
For Each prod in oProducts // (2)
prod.Quantity = GetQuantity(prod.ProductID)
Next
Это вызывает выбор из базы данных. Внутри цикла вы изменяете возвращаемый объект. В LINQ to Objects это не будет иметь никакого эффекта , , потому что в следующий раз, когда вы выполните итерацию IQueryable, он будет выполнен заново. Тем не менее, объекты Entity являются особенными. Отключение их помечает, что сущность изменяется в контексте. Вызов SaveChanges()
позже сохранит эти изменения в базе данных.
Важно отметить, однако, что вы не изменили переменную IQueryable
oProducts
на всех , выполнив это. Это все еще ссылка на запрос, который будет выполняться каждый раз, когда он повторяется. Это не список. Если вы хотите список, вам нужно позвонить ToList()
или ToArray()
.
Следующий запрос (3) создает новый IQueryable на основе оригинального oProducts
. При повторении это приведет к созданию нового SQL, который будет почти таким же, как и исходный запрос, за исключением того порядка, который вы добавили. Опять же, oProducts
- это запрос, а не список.
Dim oOrderedProducts = From p in oProducts _ // 3
Order By p.Quantity Ascending _
Select p
Наконец, ваш код выполняет новый запрос к базе данных на основе IQueryable, который вы определили выше. Выполняя этот запрос, он объединяет информацию, полученную из базы данных, со сведениями о мутации, которую вы сделали выше, из контекста объекта. Поскольку упорядочение основано на заданном вами запросе, оно выполняется на сервере базы данных с использованием информации в базе данных. Поскольку информация из базы данных объединяется с информацией из контекста объекта, вы все равно видите мутацию, которую вы выполнили с данными выше, в (2).
For Each prod in oOrderedProducts
Response.Write(prod.Quantity.ToString())
'*** The Quantities are stored in the collection properly but it doesn't order by the Quantity field.
Next