Упорядочить по измененному объекту Entity Framework - PullRequest
2 голосов
/ 25 января 2010

Я получаю коллекцию объектов Entity Framework из моей таблицы Products, которая называется oProducts. Я перебираю коллекцию и настраиваю поле Количество из отдельной функции. Прежде чем я напишу отображение объектов в HTML, я хочу отсортировать их по количеству. Итак, я использую LINQ для создания новой коллекции и пытаюсь сделать заказ из коллекции объектов, которую я только что изменил. Измененные значения определенно находятся в коллекции объектов и правильно выводятся, но сортировка не работает в измененном поле. Кто-нибудь знает, что я пропускаю или лучший способ попробовать это?

Dim oProducts = From p in ctx.Products _
                Where p.Active = True _
                Select p

For Each prod in oProducts
    prod.Quantity = GetQuantity(prod.ProductID)
Next

Dim oOrderedProducts = From p in oProducts _
                       Order By p.Quantity Ascending _
                       Select p

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

Ответы [ 3 ]

4 голосов
/ 26 января 2010

Есть несколько вещей, которые нужно запомнить:

  1. Выполнение From p in ctx.Products _ будет всегда выбирать из базы данных.
  2. LINQ ленив. Он не выполнит выбор базы данных, пока вы не выполните итерацию, а если вы выполните итерацию дважды, это сделает выбор базы данных дважды.
  3. Как данные, считанные из базы данных, объединяются с данными, уже находящимися в 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
1 голос
/ 26 января 2010

Вам не нужно использовать 3 последовательных выражения LINQ, объединять их в одно, используя проекцию, либо в анонимный тип (как я это сделал здесь), либо в реальное. Это, ниже, должно работать

var oProducts = From p in ctx.Products
                Where p.Active == True
                orderby p.Quantity Ascending
                select new 
                {
                    Quantity = GetQuantity(p.ProductID)
                    // ... assign other properties too
                }

foreach ( var prod in oProducts )
{
  // do your output
}
0 голосов
/ 26 января 2010

Как насчет этого?

Dim oProducts = From p in ctx.Products _
                Where p.Active = True _
                Select p

For Each prod in oProducts
    prod.Quantity = GetQuantity(prod.ProductID)
Next

Dim oOrderedProducts = oProducts.OrderBy(Function(p) p.Quantity)
...