Como você pode fazer paginação com o NHibernate?
-
09-06-2019 - |
Pergunta
Por exemplo, quero preencher um controle gridview em uma página da web ASP.NET com apenas os dados necessários para o número de linhas exibidas.Como o NHibernate pode suportar isso?
Solução
ICriteria
tem um SetFirstResult(int i)
método, que indica o índice do primeiro item que você deseja obter (basicamente a primeira linha de dados da sua página).
Também tem um SetMaxResults(int i)
método, que indica o número de linhas que você deseja obter (ou seja, o tamanho da sua página).
Por exemplo, este objeto de critérios obtém os primeiros 10 resultados da sua grade de dados:
criteria.SetFirstResult(0).SetMaxResults(10);
Outras dicas
Você também pode aproveitar o recurso Futures do NHibernate para executar a consulta e obter a contagem total de registros, bem como os resultados reais em uma única consulta.
Exemplo
// 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>();
Para obter a contagem total de registros, faça o seguinte:
int iRowCount = rowCount.Value;
Uma boa discussão sobre o que os futuros oferecem é aqui.
Do NHibernate 3 e superior, você pode usar QueryOver<T>
:
var pageRecords = nhSession.QueryOver<TEntity>()
.Skip((PageNumber - 1) * PageSize)
.Take(PageSize)
.List();
Você também pode ordenar explicitamente seus resultados assim:
var pageRecords = nhSession.QueryOver<TEntity>()
.OrderBy(t => t.AnOrderFieldLikeDate).Desc
.Skip((PageNumber - 1) * PageSize)
.Take(PageSize)
.List();
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); }
}
Ao paginar dados, existe outra maneira de obter o resultado digitado do MultiCriteria ou todos fazem o mesmo como eu?
Obrigado
Que tal usar o Linq to NHibernate conforme discutido em esta postagem do blog por Ayende?
Amostra de código:
(from c in nwnd.Customers select c.CustomerID)
.Skip(10).Take(10).ToList();
E aqui está uma postagem detalhada do blog da equipe do NHibernate em Acesso a dados com NHibernate incluindo a implementação de paginação.
Provavelmente em um GridView você desejará mostrar uma fatia de dados mais o número total de linhas (rowcount) da quantidade total de dados que corresponderam à sua consulta.
Você deve usar uma MultiQuery para enviar a consulta Select count(*) e as consultas .SetFirstResult(n).SetMaxResult(m) para seu banco de dados em uma única chamada.
Observe que o resultado será uma lista que contém 2 listas, uma para a fatia de dados e outra para a contagem.
Exemplo:
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];
Sugiro que você crie uma estrutura específica para lidar com a paginação.Algo como (sou programador Java, mas deve ser fácil de mapear):
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()
}
Não forneci uma implementação, mas você poderia usar os métodos sugeridos por @Jon.Aqui está um boa discussão para você dar uma olhada.