22 votes

La méthode 'Skip' est uniquement prise en charge pour une entrée triée dans LINQ to Entities

Quelle pourrait être la cause de ce problème?

public ActionResult Index(int page = 0)
{
    const int pageSize = 3;
    var areas = repo.FindAllAreas();
    var paginatedArea = new PaginatedList(areas, page, pageSize);

    return View(paginatedArea);
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UTEPSA.Controllers
{
    class PaginatedList : List
    {
        public int PageIndex { get; private set; }
        public int PageSize { get; private set; }
        public int TotalCount { get; private set; }
        public int TotalPages { get; private set; }
        public PaginatedList(IQueryable source, int pageIndex, int pageSize)
        {
            PageIndex = pageIndex;
            PageSize = pageSize;
            TotalCount = source.Count();
            TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
//ERREUR ICI-->>this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
        }
        public bool HasPreviousPage
        {
            get
            {
                return (PageIndex > 0);
            }
        }
        public bool HasNextPage
        {
            get
            {
                return (PageIndex + 1 < TotalPages);
            }
        }
    }
}

Des suggestions?

33voto

Wagner Silveira Points 1138

Il semble que l'erreur est exactement ce qu'elle dit. "Skip n'est autorisé que sur les entrées triées". En recherchant cette erreur, j'ai trouvé cela.

Il devrait être corrigé si vous incluez un OrderBy avant Skip :

source.orderBy(???).Skip(PageIndex * PageSize).Take(PageSize)); 

Cela pourrait poser un problème étant donné que vous passez un objet générique T. Vous pourriez avoir besoin d'étendre votre classe pour recevoir un autre paramètre indiquant l'élément de tri.

3voto

mavore Points 39

Ce qui a fonctionné (utilisez d'abord IOrderedQueryable):

http://msdn.microsoft.com/en-us/library/bb738702.aspx

 IOrderedQueryable produits = context.Products
        .OrderBy(p => p.ListPrice);

IQueryable tousSauf3PremiersProduits = produits.Skip(3);

Console.WriteLine("Tous sauf les 3 premiers produits :");
foreach (Product produit in tousSauf3PremiersProduits)
{
    Console.WriteLine("Nom : {0} \t ID : {1}",
        produit.Name,
        produit.ProductID);
}

2voto

Zooba Points 6440

Un IQueryable n'a pas d'ordre, donc dire "ignorer les x prochains éléments" n'a pas de sens.

Si vous incluez une clause order by (ou éventuellement un appel AsEnumerable() - non testé), alors vos données prennent un ordre et Skip et Take ont maintenant du sens.

2voto

Peter Shen Points 41

J'ai voulu valider cela en exécutant l'équivalent SQL d'une requête LINQ skip/take similaire.

SELECT * FROM [table]
--order by [column] //omis!
OFFSET 10 ROWS
FETCH NEXT 15 rows only

Remarquez que lorsque la clause order-by est omise, l'erreur SQL est beaucoup moins informative :

"Utilisation invalide de l'option NEXT dans l'instruction FETCH."

Le "tri d'entrée" est donc réellement requis au niveau de la base de données. Bravo à LINQ pour aider les développeurs à écrire des requêtes SQL avancées !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X