Come puoi eseguire il paging con NHibernate?


107

Ad esempio, voglio popolare un controllo gridview in una pagina Web ASP.NET con solo i dati necessari per il numero di righe visualizzate. Come può NHibernate supportarlo?

Risposte:


111

ICriteriaha un SetFirstResult(int i)metodo, che indica l'indice del primo elemento che desideri ottenere (in pratica la prima riga di dati nella tua pagina).

Ha anche un SetMaxResults(int i)metodo, che indica il numero di righe che desideri ottenere (cioè, la dimensione della tua pagina).

Ad esempio, questo oggetto criteri ottiene i primi 10 risultati della griglia di dati:

criteria.SetFirstResult(0).SetMaxResults(10);

1
Questo è più o meno come sarebbe la sintassi da Linq (a NH) comunque - Bello.
MotoWilliams

13
È importante notare che sarà necessario eseguire una transazione separata per recuperare il conteggio totale delle righe per eseguire il rendering del cercapersone.
Kevin Pang

1
Ciò esegue una query SELECT TOP in SQL Server. Provalo con SetFirstResult (1) .SetMaxResult (2);
Chris S,

4
Questo commento precedente utilizza NHibernate.Dialect.MsSql2000Dialect non NHibernate.Dialect.MsSql2005Dialect
Chris S

IQuery ha le stesse funzioni, quindi può essere utilizzato anche con HQL.
goku_da_master

87

Puoi anche sfruttare la funzionalità Futures in NHibernate per eseguire la query e ottenere il conteggio totale dei record e i risultati effettivi in ​​una singola query.

Esempio

 // Get the total row count in the database.
var rowCount = this.Session.CreateCriteria(typeof(EventLogEntry))
    .Add(Expression.Between("Timestamp", startDate, endDate))
    .SetProjection(Projections.RowCount()).FutureValue<Int32>();

// Get the actual log entries, respecting the paging.
var results = this.Session.CreateCriteria(typeof(EventLogEntry))
    .Add(Expression.Between("Timestamp", startDate, endDate))
    .SetFirstResult(pageIndex * pageSize)
    .SetMaxResults(pageSize)
    .Future<EventLogEntry>();

Per ottenere il conteggio totale dei record, procedi come segue:

int iRowCount = rowCount.Value;

Una buona discussione su ciò che i Futures ti danno è qui .


3
Questo è fantastico. I futures funzionano esattamente come i multicriteri senza la complessità sintattica dei multicriteri.
DavGarcia

Dopo aver letto il post sui Futures, mi chiedo se dovrei usare Future per tutte le mie query sul database ... Qual è lo svantaggio? :)
hakksor

46

Da NHibernate 3 e versioni successive, puoi utilizzare QueryOver<T>:

var pageRecords = nhSession.QueryOver<TEntity>()
            .Skip((PageNumber - 1) * PageSize)
            .Take(PageSize)
            .List();

Potresti anche voler ordinare esplicitamente i tuoi risultati in questo modo:

var pageRecords = nhSession.QueryOver<TEntity>()
            .OrderBy(t => t.AnOrderFieldLikeDate).Desc
            .Skip((PageNumber - 1) * PageSize)
            .Take(PageSize)
            .List();

.Skip(PageNumber * PageSize)in questo modo, se la dimensione della pagina è 10, non recupererà mai le prime 10 righe. Sto modificando per rendere la formula corretta. Supponendo che concettualmente, PageNumbernon dovrebbe essere 0. Dovrebbe essere minimo 1.
Amit Joshi

31
public IList<Customer> GetPagedData(int page, int pageSize, out long count)
        {
            try
            {
                var all = new List<Customer>();

                ISession s = NHibernateHttpModule.CurrentSession;
                IList results = s.CreateMultiCriteria()
                                    .Add(s.CreateCriteria(typeof(Customer)).SetFirstResult(page * pageSize).SetMaxResults(pageSize))
                                    .Add(s.CreateCriteria(typeof(Customer)).SetProjection(Projections.RowCountInt64()))
                                    .List();

                foreach (var o in (IList)results[0])
                    all.Add((Customer)o);

                count = (long)((IList)results[1])[0];
                return all;
            }
            catch (Exception ex) { throw new Exception("GetPagedData Customer da hata", ex); }
      }

Quando si impaginano i dati c'è un altro modo per ottenere il risultato digitato da MultiCriteria o tutti fanno lo stesso proprio come me?

Grazie


23

Che ne dici di usare Linq per NHibernate come discusso in questo post sul blog di Ayende?

Esempio di codice:

(from c in nwnd.Customers select c.CustomerID)
        .Skip(10).Take(10).ToList(); 

Ed ecco un post dettagliato del blog del team di NHibernate sull'accesso ai dati con NHibernate che include l'implementazione del paging.


Nota che linq per Nhibernate è nel pacchetto contrib e non è incluso nella versione 2.0 di NHibernate
Richard

11

Molto probabilmente in un GridView vorrai mostrare una porzione di dati più il numero totale di righe (conteggio righe) della quantità totale di dati che corrispondono alla tua query.

È necessario utilizzare un MultiQuery per inviare sia la query Select count (*) che le query .SetFirstResult (n) .SetMaxResult (m) al database in una singola chiamata.

Nota che il risultato sarà un elenco che contiene 2 elenchi, uno per la sezione di dati e uno per il conteggio.

Esempio:

IMultiQuery multiQuery = s.CreateMultiQuery()
    .Add(s.CreateQuery("from Item i where i.Id > ?")
            .SetInt32(0, 50).SetFirstResult(10))
    .Add(s.CreateQuery("select count(*) from Item i where i.Id > ?")
            .SetInt32(0, 50));
IList results = multiQuery.List();
IList items = (IList)results[0];
long count = (long)((IList)results[1])[0];

6

Ti suggerisco di creare una struttura specifica per gestire l'impaginazione. Qualcosa del tipo (sono un programmatore Java, ma dovrebbe essere facile da mappare):

public class Page {

   private List results;
   private int pageSize;
   private int page;

   public Page(Query query, int page, int pageSize) {

       this.page = page;
       this.pageSize = pageSize;
       results = query.setFirstResult(page * pageSize)
           .setMaxResults(pageSize+1)
           .list();

   }

   public List getNextPage()

   public List getPreviousPage()

   public int getPageCount()

   public int getCurrentPage()

   public void setPageSize()

}

Non ho fornito un'implementazione, ma potresti usare i metodi suggeriti da @Jon . Ecco una buona discussione da dare un'occhiata.


0

Non è necessario definire 2 criteri, è possibile definirne uno e clonarlo. Per clonare i criteri di nHibernate puoi usare un semplice codice:

var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.