如何将ROW_NUMBER添加到LINQ查询或实体?

我被这个简单的数据问题困住了。

我正在使用entity framework,并有一个产品数据库。 我的结果页面会返回这些产品的分页列表。 现在我的结果按每个产品的销售数量sorting,所以我的代码如下所示:

return Products.OrderByDescending(u => u.Sales.Count()); 

这将返回我的实体的IQueryable数据集,按销售数量sorting。

我希望我的结果页面显示每个产品的等级(在数据集中)。 我的结果应该是这样的:

 Page #1 1. Bananas 2. Apples 3. Coffee Page #2 4. Cookies 5. Ice Cream 6. Lettuce 

我期待,我只是想在我的结果中使用SQL ROW_NUMBERvariables添加一列…但我不知道如何将此列添加到我的结果数据表。

我的结果页面确实包含了一个foreach循环,但是因为我使用了一个分页集合,我猜测用这个数字来伪造一个排名数字并不是最好的方法。

所以我的问题是,在这种情况下如何添加一个ROW_NUMBER列到我的查询结果?

使用Select的索引过载 :

 var start = page * rowsPerPage; Products.OrderByDescending(u => u.Sales.Count()) .Skip(start) .Take(rowsPerPage) .AsEnumerable() .Select((u, index) => new { Product = u, Index = index + start }); 

这是一个漫长的回答。 首先创build一个类来容纳数字/项目对,如下所示:

 public class NumberedItem<T> { public readonly int Number; public readonly T Item; public NumberedItem(int number, T item) { Item = item; Number = number; } } 

接下来是一个项目的页面抽象(编号或不)。

 class PageOf<T> : IEnumerable<T> { private readonly int startsAt; private IEnumerable<T> items; public PageOf(int startsAt, IEnumerable<T> items) { this.startsAt = startsAt; this.items = items; } public IEnumerable<NumberedItem<T>> NumberedItems { get { int index = 0; foreach (var item in items) yield return new NumberedItem<T>(startsAt + index++, item); yield break; } } public IEnumerator<T> GetEnumerator() { foreach (var item in items) yield return item; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } 

一旦你有了,你可以使用这个“分页”一个特定的可查询集合:

 class PaginatedQueryable<T> { private readonly int PageSize; private readonly IQueryable<T> Source; public PaginatedQueryable(int PageSize, IQueryable<T> Source) { this.PageSize = PageSize; this.Source = Source; } public PageOf<T> Page(int pageNum) { var start = (pageNum - 1) * PageSize; return new PageOf<T>(start + 1, Source.Skip(start).Take(PageSize)); } } 

最后一个很好的扩展方法来掩盖丑陋的:

 static class PaginationExtension { public static PaginatedQueryable<T> InPagesOf<T>(this IQueryable<T> target, int PageSize) { return new PaginatedQueryable<T>(PageSize, target); } } 

这意味着你现在可以做到这一点:

 var products = Products.OrderByDescending(u => u.Sales.Count()).InPagesOf(20).Page(1); foreach (var product in products.NumberedItems) { Console.WriteLine("{0} {1}", product.Number, product.Item); } 

实际上使用OrderBy,然后Skip + Take在EF 4.5中生成ROW_NUMBER(可以使用SQL Profiler进行检查)。

我正在寻找一种方法来做同样的事情,通过简化Craig的回答,我能够得到所需的东西:

 var start = page * rowsPerPage; Products.OrderByDescending(u => u.Sales.Count()) .Skip(start) .Take(rowsPerPage) .ToList(); 

顺便说一下,生成的SQL使用ROW_NUMBER> start和TOP rowsPerPage。

尝试这个

 var x = Products.OrderByDecending(u => u.Sales.Count()); var y = x.ToList(); for(int i = 0; i < y.Count; i++) { int myNumber = i; // this is your order number } 

只要列表保持相同的顺序,这应该发生,除非销售号码改变。 你可以得到一个准确的数字;

也有这样的做法。

 var page = 2; var count = 10; var startIndex = page * count; var x = Products.OrderByDecending(u => u.Sales.Count()); var y = x.Skip(startIndex).Take(count); 

这给了页面的开始索引,再加上它给你一个小的销售集合显示在页面上。 你只需从startIndex处开始计算你的网站。