2009-07-22 9 views
23

Jestem zaskoczony tym łatwym problemem z danymi.Jak dodać ROW_NUMBER do kwerendy LINQ lub Entity?

Używam struktury Entity i mam bazę danych produktów. Moja strona wyników zwraca listę stron w paginacji tych produktów. Teraz moje wyniki są uporządkowane według liczby sprzedaży każdego produktu, więc mój kod wygląda następująco:

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

ta zwraca IQueryable zestawu danych z moich jednostek, uporządkowane według liczby sprzedaży.

Chcę, aby na stronie z wynikami wyświetlała się pozycja każdego produktu (w zbiorze danych). Moje wyniki powinny wyglądać następująco:

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

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

Oczekuję, że po prostu chcę dodać kolumnę w moich wyników z wykorzystaniem zmiennej SQL ROW_NUMBER ... ale nie wiem jak dodać tę kolumnę do mojego wyniki są datatable.

Moja wynikowa strona zawiera pętlę foreach, ale ponieważ używam zestawu stronicowanego, zgaduję, że użycie tej liczby do sfałszowania numeru pozycji NIE byłoby najlepszym rozwiązaniem.

Moje pytanie brzmi: jak dodać kolumnę ROW_NUMBER do wyników zapytania w tym przypadku?

Odpowiedz

0

Spróbuj

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 
} 

Dopóki lista pozostaje w tej samej kolejności, co powinno się zdarzyć, chyba że liczba sprzedaży zmienia. Możesz uzyskać dokładną liczbę;

Istnieje również ten sposób robienia tego.

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

Daje to indeks początkowy strony, a także daje niewielki zestaw sprzedaży do wyświetlenia na stronie. Po prostu zaczynasz liczenie na swojej stronie na startIndex.

25

Użyj 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

Haha. W pewnym sensie to wdrażałem ręcznie, ale to działa. –

+0

Nie wiem, czy to ma znaczenie, ale to będzie trudne do przekazania, ponieważ jest to obiekt anonimowy. –

+2

Nie musisz używać typu anonimowego. Utwórz typ nieanonimowy i użyj go, jeśli potrzebujesz. To tylko przykład. –

1

Oto długo zdyszany odpowiedź. Najpierw utworzyć klasę do domu numer/parę artykuł tak:

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

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

Następnie przychodzi abstrakcji wokół stronie pozycji (numerowanej lub nie):

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

Kiedy już, że można " paginate”szczególna kolekcja queryable pomocą tego:

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

i wreszcie piękny metodę rozszerzenia na pokrycie brzydki:

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

Czyli teraz możesz to zrobić:

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

rzeczywiście przy orderby a następnie Przejdź + Weź generuje ROW_NUMBER w EF 4.5 (można sprawdzić w programie SQL Profiler).

szukałem sposobu, aby zrobić to samo prosicie i udało mi się dostać to, czego potrzebuję poprzez uproszczenie Craiga odpowiedź:

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

przy okazji, generowanych zastosowań SQL ROW_NUMBER> start i TOP rowsPerPage.

Powiązane problemy