2010-08-09 11 views
10

Che cosa potrebbe causare questo problema?Il metodo 'Salta' è supportato solo per l'input ordinato in LINQ alle entità

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

    return View(paginatedArea); 
} 


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

namespace UTEPSA.Controllers 
{ 
    class PaginatedList<T> : List<T> 
    { 
     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<T> source, int pageIndex, int pageSize) 
     { 
      PageIndex = pageIndex; 
      PageSize = pageSize; 
      TotalCount = source.Count(); 
      TotalPages = (int)Math.Ceiling(TotalCount/(double)PageSize); 
//ERROR HERE->>this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize)); 
     } 
     public bool HasPreviousPage 
     { 
      get 
      { 
       return (PageIndex > 0); 
      } 
     } 
     public bool HasNextPage 
     { 
      get 
      { 
       return (PageIndex + 1 < TotalPages); 
      } 
     } 
    } 
} 

Qualche suggerimento?

+0

Hai guardato la libreria mvccontrib? Contiene un componente cercapersone: http://www.jeremyskinner.co.uk/2010/03/14/mvccontrib-grid-part-6-sorting/. Non sono sicuro di come si avvicini a questo problema ... – jeroenh

risposta

17

Sembra che l'errore sia esattamente quello che dice. "Salta è consentito solo su input ordinati". Ricerca di questo errore, ho trovato questo:

http://weblogs.asp.net/rajbk/archive/2009/09.aspx

Dovrebbe essere fissato se si include un OrderBy prima Skip:

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

che potrebbe essere un problema dal momento che si sta passando un generico oggetto T. Potrebbe essere necessario espandere la classe per ricevere un altro parametro per indicare l'ordine per elemento.

Spero che questo aiuti.

+0

Dall'articolo: Questo problema sembra essere stato risolto nel framework .NET 4.0 [per linq-to-sql, non linq-to-entities] ... – jeroenh

+0

Do not seleziona la proprietà in base al quale ordinare se è nullo! poiché la tua impaginazione non funziona correttamente. – Elnaz

0

Un IQueryable non ha un ordine, quindi dire "ignorare il prossimo x elementi" non ha alcun senso.

Se si include una clausola di order by (o, eventualmente, un AsEnumerable() chiamata - testato) quindi i dati prende un ordine e Skip e Take sono ora sensibile.

+5

Non si desidera aggiungere AsEnumerable. Ciò eliminerebbe la ragione principale del paging, che è solo per recuperare una quantità limitata di dati dal database ... Aggiungendo AsEnumerable() si attiverà a TUTTO e si applicherà il paging in-memory. – jeroenh

+1

Avete provato questo (o avete una fonte), o lo state assumendo? Calling ToList o ToArray introdurranno certamente tutto, ma non c'è nulla nel contratto di AsEnumerable che lo costringa a recuperare tutti i dati prima di restituire i primi (e successivi) elementi. – Zooba

+2

L'esecuzione di .Skip() e .Take() su un oggetto IEnumerable comporterà la restituzione di TUTTI i risultati dal database quando viene chiamato .ToList(). In questa situazione, l'impaginazione effettiva viene eseguita in memoria. Ho provato questo utilizzando SQL Server Profiler e la query sql generata non ha avuto alcuna limitazione di impaginazione. – quakkels

1

che viene lavorato (primo utilizzo IOrderedQueryable):

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

IOrderedQueryable<Product> products = context.Products 
     .OrderBy(p => p.ListPrice); 

IQueryable<Product> allButFirst3Products = products.Skip(3); 

Console.WriteLine("All but first 3 products:"); 
foreach (Product product in allButFirst3Products) 
{ 
    Console.WriteLine("Name: {0} \t ID: {1}", 
     product.Name, 
     product.ProductID); 
} 
1

ho voluto convalidare questo eseguendo l'equivalente SQL di un simile LINQ SKIP/prendere interrogazione.

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

Nota che quando la clausola order-by viene omessa, l'errore SQL è molto meno informativo:

"Invalid usage of the option NEXT in the FETCH statement." 

Così il "input ordinato" è effettivamente necessaria sul livello del database. Complimenti a LINQ per aiutare gli sviluppatori a scrivere istruzioni SQL avanzate!

Problemi correlati