Jak możesz stronicować za pomocą NHibernate?

107

Na przykład chcę wypełnić formant widoku siatki na stronie sieci Web ASP.NET tylko danymi niezbędnymi dla wyświetlonej liczby wierszy. Jak NHibernate może to wspierać?

Promień
źródło

Odpowiedzi:

111

ICriteriama SetFirstResult(int i)metodę, która wskazuje indeks pierwszego elementu, który chcesz uzyskać (w zasadzie pierwszy wiersz danych na twojej stronie).

Posiada również SetMaxResults(int i)metodę, która wskazuje liczbę wierszy, które chcesz uzyskać (tj. Rozmiar strony).

Na przykład ten obiekt kryteriów pobiera pierwszych 10 wyników siatki danych:

criteria.SetFirstResult(0).SetMaxResults(10);
Jon Limjap
źródło
1
Tak i tak wyglądałaby składnia Linq (do NH) - fajnie.
MotoWilliams,
13
Ważne jest, aby pamiętać, że będziesz musiał wykonać oddzielną transakcję, aby pobrać całkowitą liczbę wierszy, aby wyrenderować pager.
Kevin Pang,
1
Spowoduje to wykonanie zapytania SELECT TOP w programie SQL Server. Spróbuj z SetFirstResult (1) .SetMaxResult (2);
Chris S,
4
To poprzedni komentarz używa NHibernate.Dialect.MsSql2000Dialect, a nie NHibernate.Dialect.MsSql2005Dialect
Chris S
IQuery ma te same funkcje, więc może być również używany z HQL.
goku_da_master
87

Możesz również skorzystać z funkcji Futures w NHibernate, aby wykonać zapytanie w celu uzyskania całkowitej liczby rekordów, a także rzeczywistych wyników w pojedynczym zapytaniu.

Przykład

 // 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>();

Aby uzyskać całkowitą liczbę rekordów, wykonaj następujące czynności:

int iRowCount = rowCount.Value;

Dobrym dyskusja co Futures dać to tutaj .

Jeremy D.
źródło
3
To jest świetne. Futures działa dokładnie tak, jak wielokryteria, bez złożoności składniowej wielokryteriów.
DavGarcia
Po przeczytaniu postu o Futures zastanawiam się, czy powinienem używać Future do wszystkich zapytań do bazy danych ... Jaka jest wada? :)
hakksor
46

Od NHibernate 3 i nowszych możesz użyć QueryOver<T>:

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

Możesz również jawnie uporządkować wyniki w następujący sposób:

var pageRecords = nhSession.QueryOver<TEntity>()
            .OrderBy(t => t.AnOrderFieldLikeDate).Desc
            .Skip((PageNumber - 1) * PageSize)
            .Take(PageSize)
            .List();
Leandro de los Santos
źródło
.Skip(PageNumber * PageSize)w ten sposób, jeśli rozmiar strony to 10, nigdy nie pobierze pierwszych 10 wierszy. Edytuję, aby poprawić formułę. Zakładając, że koncepcyjnie PageNumbernie powinno być 0. Powinno być minimum 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); }
      }

Czy podczas stronicowania danych istnieje inny sposób uzyskania wpisanego wyniku z MultiCriteria, czy też wszyscy robią to samo, tak jak ja?

Dzięki

Barbaros Alp
źródło
23

Co powiesz na użycie Linq do NHibernate, jak omówiono w tym poście na blogu Ayende?

Przykład kodu:

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

A oto szczegółowy post blogu zespołu NHibernate na temat dostępu do danych z NHibernate, w tym implementacji stronicowania.

NotMyself
źródło
Uwaga linq do Nhibernate jest w pakiecie Contrib i nie jest uwzględniony w wydaniu NHibernate 2.0
Richard
11

Najprawdopodobniej w GridView będziesz chciał wyświetlić wycinek danych oraz łączną liczbę wierszy (rowcount) z łącznej ilości danych, które pasują do zapytania.

Powinieneś użyć MultiQuery, aby wysłać zarówno zapytanie Select count (*), jak i .SetFirstResult (n) .SetMaxResult (m) do bazy danych w jednym wywołaniu.

Zwróć uwagę, że wynikiem będzie lista zawierająca 2 listy, jedną dla wycinka danych i jedną dla liczby.

Przykład:

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];
zadam
źródło
6

Proponuję stworzyć specjalną strukturę zajmującą się paginacją. Coś takiego (jestem programistą Java, ale to powinno być łatwe do zmapowania):

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()

}

Nie dostarczyłem implementacji, ale możesz użyć metod sugerowanych przez @Jon . Oto dobra dyskusja do obejrzenia.

Marcio Aguiar
źródło
0

Nie musisz definiować 2 kryteriów, możesz zdefiniować jedno i sklonować. Aby sklonować kryteria nHibernate, możesz użyć prostego kodu:

var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();
Marcin
źródło