Pregunta

Estoy confundido por este problema de datos fácil.

Estoy usando el marco de la entidad y tienen una base de datos de productos. Mi página de resultados devuelve una lista paginada de estos productos. En este momento mis resultados son ordenados por el número de ventas de cada producto, por lo que mi código es el siguiente:

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

Esto devuelve un conjunto de datos IQueryable de mis entidades, ordenados por el número de ventas.

Quiero que mi página de resultados para mostrar el rango de cada producto (en el conjunto de datos). Mis resultados deben tener este aspecto:

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

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

Estoy esperando que sólo quiero agregar una columna en mis resultados utilizando la variable de SQL ROW_NUMBER ... pero no sé cómo añadir esta columna a los resultados de tabla de datos.

Mi página resultante contiene un bucle foreach, pero ya que estoy usando un conjunto paginado supongo usando ese número de falsificar un número de clasificación no sería el mejor enfoque.

Así que mi pregunta es, ¿cómo puedo añadir una columna ROW_NUMBER a mis resultados de la consulta en este caso?

No hay solución correcta

Otros consejos

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

Actually using OrderBy and then Skip + Take generates ROW_NUMBER in EF 4.5 (you can check with SQL Profiler).

I was searching for a way to do the same thing you are asking for and I was able to get what I need through a simplification of Craig's answer:

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

By the way, the generated SQL uses ROW_NUMBER > start and TOP rowsPerPage.

Here is a long winded answer. First create a class to house the number/item pair like so:

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

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

Next comes an abstraction around a page of items (numbered or not):

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

Once you have that you can "Paginate" a particular queryable collection using this:

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

And finally a nice extension method to cover the ugly:

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

Which means you can now do this:

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

Try this

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
}

As long as the list stays in the same order, which should happen unless the sales number changes. You could be able to get an accurate count;

There is also this way of doing it.

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

This gives the start index for the page, plus it gives you a small set of sales to display on the page. You just start the counting on your website at startIndex.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top