简体   繁体   English

在修改后的实体框架对象上订购

[英]Order By on a modified Entity Framework object

I'm getting an Entity Framework object collection from my Products table called oProducts. 我从我的Products表(称为oProducts)中获得了一个Entity Framework对象集合。 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. 在用HTML写出对象显示之前,我想按数量对它们进行排序。 So, I am using LINQ to create a new collection and try to order from the object collection that I just modified. 因此,我正在使用LINQ创建一个新的集合,并尝试从刚修改的对象集合中订购。 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. From p in ctx.Products _执行From p in ctx.Products _始终从数据库中选择。
  2. LINQ is lazy. LINQ很懒。 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. 从数据库读取的数据与ObjectContext已存在的数据的组合方式将根据您执行的查询的MergeOption而有所不同。 But it will always happen after the SQL is executed. 但是它总是执行SQL 之后发生。

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. 该位(1)创建一个IQueryable<Product> ,该IQueryable<Product>可用作迭代或定义其他查询的基础。 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. 下一位(2)迭代上面定义的IQueryable。

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. 在LINQ to Objects中,这完全无效,因为下次您迭代IQueryable时,它将重新执行。 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. 稍后调用SaveChanges()会将那些修改保存到数据库中。

It's important to note, however, that you have not changed the IQueryable variable oProducts at all by doing this. 但必须注意的是,你还没有改变这一点很重要IQueryable变量oProducts做这个 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() . 如果需要列表,则需要调用ToList()ToArray()

The following query (3) creates a new IQueryable based on the original oProducts . 以下查询(3)基于原始oProducts创建一个新的IQueryable。 When iterated, this will produce new SQL which does much the same as the original query, except for the ordering you've added. 进行迭代时,这将产生新的SQL,除了添加的顺序外,它与原始查询的功能大致相同。 Again, oProducts is a query, not a list. 同样, oProducts是查询,而不是列表。

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. 最后,您的代码根据您在上面定义的IQueryable执行新的数据库查询。 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). 因为来自数据库的信息与来自对象上下文的信息合并,所以您仍然可以在(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. 您不需要使用3个连续的LINQ表达式,使用投影将它们组合为一个,可以是匿名类型(如我在此所做的)或真实的类型。 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM