Paginare un controllo mediante LINQ to Entities

In un sito pubblico seo-friendly è bene evitare di usare la paginazione automatica prodotta da un GridView o dal  DataPager di un ListView in quanto si genera codice JavaScript non interpretabile dai motori di ricerca.

Per motivi di prestazioni non usare neanche la paginazione manuale tramite DataSet poiché ad ogni richiesta vengono inutilmente trasferite tutte le righe dal DB alla pagina Asp.Net sul server.

In modo analogo alla paginazione tramite una stored procedure, la paginazione manuale tramite Entity Framework avviene invece a livello di SQL quindi vengono trasferiti dal data base alla pagina aspx solo i dati necessari.

Questa tecnica è stata utilizzata nella pagina di elenco articoli del sito Dev-oClock.com 

Paginare manualmente un controllo Asp.Net

Creare un Entity Data Model per il sito web come spiegato in un articolo precedente.

Aggiungere poi il controllo da paginare; in questo caso ho usato un GridView ma lo stesso metodo è applicabile anche ad altri controlli quali Repeater e ListView.
Aggiungere anche una label che conterrà i numeri delle pagine per la navigazione.

<asp:GridView ID="GridView1" runat="server"></asp:GridView>
<br />
<asp:Label ID="lblPaginazione" runat="server"></asp:Label>

Tramite Linq to Entities si estraggono di volta in volta solo i record da mostrare nella pagina web.
Con il comando Take si sceglie il numero di righe da estrarre, mentre con Skip si imposta il numero di righe da ignorare prima di iniziare a leggere. E' un funzionamento simile al parametro LIMIT di MySql.

'importo il namespace per il modello EF
Imports NorthwindModel

Partial Class Paginazione
    Inherits System.Web.UI.Page

	Dim RowsPerPage As Short
	Dim CurrentPage As Short
	Dim TotPages As Short

	Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load

		If Not Page.IsPostBack Then

			'stabilisco il numero di elementi da mostrare in ogni pagina
			RowsPerPage = 15

			'leggo dalla query string la pagina attuale, per default = 1 
			If Request.QueryString.Get("page") IsNot Nothing Then
				CurrentPage = CType(Request.QueryString.Get("page"), Short)
			Else
				CurrentPage = 1
			End If

			Using myEntities As New NorthwindEntities

				'estraggo solo gli elementi della pagina desiderata usando Skip e Take
				Dim Prodotti = (From Product In myEntities.Products.Include("Category")
				 Where Product.Discontinued = False
				 Order By Product.ProductName
				 Select New With {
				  Product.ProductID,
				  Product.ProductName,
				  .Available = Product.UnitsInStock
				 }).Skip((CurrentPage - 1) * RowsPerPage).Take(RowsPerPage)

				'popolo il controllo Asp.Net (si può usare anche un ListView o un Repeater) 
				GridView1.DataSource = Prodotti
				GridView1.DataBind()

				'calcolo il numero totale di prodotti per poter poi ricavare il numero di pagine
				Dim TotProdotti = (From Product In myEntities.Products
				  Where Product.Discontinued = False
				  Order By Product.ProductName
				  Select New With {Product.ProductID}).Count()

				totPages = (TotProdotti / RowsPerPage)
				If (RowsPerPage * TotPages) < TotProdotti Then
					TotPages += 1
				End If

				'numerini per la paginazione
				If TotPages > 1 Then	'se c'è solo una pagina non ha senso mostrare i numerini
					For i As Short = 1 To TotPages
						If i <> CurrentPage Then
							lblPaginazione.Text &= "<a href=""?page=" & i & """>" & i & "</a>"
						Else
							lblPaginazione.Text &= "<b>" & i & "</b>"  'la pagina attuale non deve essere un link
						End If
						If i < TotPages Then
							lblPaginazione.Text &= "&nbsp;-&nbsp;"
						End If
					Next
				End If
			End Using
		End If
	End Sub
End Class

Autore: Sergio Roberto Boarina