Там несколько вещей, которые нужно помнить:
- Ведение
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
Этот код приведет к ошибке выполнения, поскольку LINQ to Entities не сможет перевести 'GetQuantity'. Один из способов - сначала вызвать «AsEnumerable()». –
Да, не удалось зарегистрировать L2E; думал Линк-К-Sql. Теперь, что произойдет, если вы вызываете ToList() или ToArray при создании oProducts? – Jay
Тогда это сработает. * Почему * это сработало, но сложнее, чем перевод на SQL; Я объясняю это в своем ответе. –