开发者

Order By on a modified Entity Framework object

I'm getting an Entity Framework object collection from my Products table called oProducts. I am looping through the collection and setting the Quantity field from a separate function. Before I write out a display of the objects in HTML, I want to sort them by the Quantity. So, I am using LINQ to create a new collection and try to order from the object collection that I just modified. The modified values are definitely in the object collection and output properly, but the sort ordering isn't working on the modified field. Does anyone know 开发者_高级运维what I'm overlooking or a better way to attempt this?

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


There a few things you need to remember:

  1. Doing From p in ctx.Products _ will always select from the database.
  2. LINQ is lazy. It will not perform the database select until you iterate, and if you iterate twice, it will do the database select twice.
  3. How data read from the database is combined with data already in the ObjectContext will vary based on the MergeOption of the query you execute. But it will always happen after the SQL is executed.

With those ideas in mind, let's consider your code:

This bit (1) creates an IQueryable<Product> which can be used as a basis for iteration or defining other queries. Note that it does not actually execute a database query.

Dim oProducts = From p in ctx.Products _  // (1)
                Where p.Active = True _
                Select p

The next bit (2) iterates the IQueryable defined above.

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

Doing so causes a selection from the database. Inside the loop, you mutate the object that's returned. In LINQ to Objects, this would have no effect whatsoever, because the next time you iterated the IQueryable it would be executed anew. However, Entity objects are special. Mutating them marks the entity is changed on the context. Calling SaveChanges() later would save those modifications to the database.

It's important to note, however, that you have not changed the IQueryable variable oProducts at all by doing this. It is still a reference to a query which will be executed every time it is iterated. It is not a list. If you want a list, you need to call ToList() or ToArray().

The following query (3) creates a new IQueryable based on the original oProducts. When iterated, this will produce new SQL which does much the same as the original query, except for the ordering you've added. Again, oProducts is a query, not a list.

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

Finally, your code executes a new database query based on the IQueryable you defined above. As it executes this query, it merges the information retrieved from the database with the knowledge about the mutation you did above from the object context. Because the ordering is based on the query you defined, it is performed on the database server, using information in the database. Because information from the database is merged with information from the object context, you still see the mutation you performed on the data above, in (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


You don't need to use the 3 consecutive LINQ expressions, combine them into one, using projection, either into an anonymous type (as I did here) or a real one. This, below, should work

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
}


How about this?

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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜