2009-07-22 4 views
23

私はこの簡単なデータの問題によって困っています。LINQクエリまたはエンティティにROW_NUMBERを追加するにはどうすればよいですか?

私はEntityフレームワークを使用しており、製品のデータベースを持っています。私の結果ページには、これらの製品のページ番号付きリストが返されます。私のコードは次のようになりますので、今の私の結果は、各製品の販売数が発注されています

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

これは、売上高の数でソートされた私のエンティティのデータセットのIQueryableを返します。

私の結果ページに(データセット内の)各製品のランクを表示したい。私の結果は次のようになります。

Page #1 
1. Bananas 
2. Apples 
3. Coffee 

Page #2 
4. Cookies 
5. Ice Cream 
6. Lettuce 

私はちょうどSQL ROW_NUMBER変数を使用して私の結果に列を追加することを期待しています...しかし、私は私にこの列を追加する方法がわかりません結果はデー​​タ可能です。

結果のページにはforeachループが含まれていますが、ページ分割されたセットを使用しているため、その番号を使用してランキング番号を偽装することは最良の方法ではありません。

私の質問は、この場合、クエリ結果にROW_NUMBER列を追加する方法です。

答えて

0

は限りリストは、販売数が変化しない限り、起こるはず同じ順序にとどまるように、この

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のウェブサイトでカウントを開始するだけです。

25

indexed overload of 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 }); 
+1

ハハ。私は手でそれを実装するようなものでしたが、それは動作します。 –

+0

これは問題なのかどうか分かりませんが、匿名のオブジェクトなので、これは回避するのが難しいでしょう。 –

+2

匿名のタイプを使用する必要はありません。非匿名型を作成し、必要に応じて使用します。それは単なる例です。 –

1

は長いったらしい答えです。まず、そのような番号/アイテムのペアを収容するためのクラスを作成します。あなたはあなたができることをしたら、「

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(); 
    } 
} 

public class NumberedItem<T> 
{ 
    public readonly int Number; 
    public readonly T Item; 

    public NumberedItem(int number, T item) 
    { 
     Item = item; 
     Number = number; 
    } 
} 

次は、アイテムのページ(番号またはしない)周りの抽象化を来ります

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); 
} 
1

実際のOrderByを使用して、テイク+スキップは(あなたがSQLプロファイラで確認することができます)EF 4.5でROW_NUMBERを生成します。

私はあなたが求めている同じことを行う方法を探していたと私はクレイグの答えの簡素化を通じて必要なものを得ることができた:ところで

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

、生成されたSQLの使用法ROW_NUMBER>開始およびTOPのrowsPerPage。

関連する問題