Wie können Sie mit NHibernate blättern?


107

Ich möchte beispielsweise ein Gridview-Steuerelement in einer ASP.NET-Webseite nur mit den Daten füllen, die für die Anzahl der angezeigten Zeilen erforderlich sind. Wie kann NHibernate dies unterstützen?

Antworten:


111

ICriteriahat eine SetFirstResult(int i)Methode, die den Index des ersten Elements angibt, das Sie erhalten möchten (im Grunde die erste Datenzeile auf Ihrer Seite).

Es gibt auch eine SetMaxResults(int i)Methode, die die Anzahl der Zeilen angibt, die Sie erhalten möchten (dh Ihre Seitengröße).

Dieses Kriterienobjekt erhält beispielsweise die ersten 10 Ergebnisse Ihres Datenrasters:

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

1
So würde die Linq (zu NH) -Syntax sowieso aussehen - Schön.
MotoWilliams

13
Es ist wichtig zu beachten, dass Sie eine separate Transaktion ausführen müssen, um die Gesamtzahl der Zeilen abzurufen, um Ihren Pager zu rendern.
Kevin Pang

1
Dadurch wird eine SELECT TOP-Abfrage in SQL Server ausgeführt. Versuchen Sie es mit SetFirstResult (1) .SetMaxResult (2);
Chris S

4
Dieser vorherige Kommentar verwendet NHibernate.Dialect.MsSql2000Dialect nicht NHibernate.Dialect.MsSql2005Dialect
Chris S

IQuery hat die gleichen Funktionen, kann also auch mit HQL verwendet werden.
goku_da_master

87

Sie können auch die Futures-Funktion in NHibernate nutzen, um die Abfrage auszuführen und die Gesamtzahl der Datensätze sowie die tatsächlichen Ergebnisse in einer einzigen Abfrage abzurufen.

Beispiel

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

Um die Gesamtzahl der Datensätze zu erhalten, gehen Sie wie folgt vor:

int iRowCount = rowCount.Value;

Eine gute Diskussion darüber, was Futures Ihnen bieten, finden Sie hier .


3
Das ist toll. Futures funktioniert genau wie Multikriterien ohne die syntaktische Komplexität von Multikriterien.
DavGarcia

Nachdem ich den Beitrag über Futures gelesen habe, frage ich mich, ob ich Future für alle meine Datenbankabfragen verwenden soll ... Was ist der Nachteil? :)
Hakksor

46

Ab NHibernate 3 können Sie Folgendes verwenden QueryOver<T>:

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

Möglicherweise möchten Sie Ihre Ergebnisse auch explizit wie folgt bestellen:

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

.Skip(PageNumber * PageSize)Auf diese Weise werden bei einer Seitengröße von 10 niemals die ersten 10 Zeilen abgerufen. Ich bearbeite, um die Formel korrekt zu machen. Angenommen, konzeptionell PageNumbersollte nicht 0 sein. Es sollte mindestens 1 sein.
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); }
      }

Gibt es beim Paging von Daten eine andere Möglichkeit, ein typisiertes Ergebnis von MultiCriteria zu erhalten, oder tun alle das Gleiche wie ich?

Vielen Dank


23

Wie wäre es mit Linq to NHibernate, wie in diesem Blog-Beitrag von Ayende beschrieben?

Codebeispiel:

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

Und hier ist ein ausführlicher Beitrag des NHibernate-Teamblogs zum Datenzugriff mit NHibernate, einschließlich der Implementierung von Paging.


Hinweis linq to Nhibernate ist im Contrib-Paket enthalten und nicht in der NHibernate 2.0-Version enthalten
Richard

11

Höchstwahrscheinlich möchten Sie in einer GridView einen Datenabschnitt plus die Gesamtzahl der Zeilen (Zeilenanzahl) der Gesamtdatenmenge anzeigen, die Ihrer Abfrage entspricht.

Sie sollten eine MultiQuery verwenden, um sowohl die Abfrage Select count (*) als auch die Abfragen .SetFirstResult (n) .SetMaxResult (m) in einem einzigen Aufruf an Ihre Datenbank zu senden.

Beachten Sie, dass das Ergebnis eine Liste ist, die zwei Listen enthält, eine für die Datenscheibe und eine für die Anzahl.

Beispiel:

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

Ich schlage vor, dass Sie eine bestimmte Struktur erstellen, um mit Paginierung umzugehen. So etwas wie (ich bin ein Java-Programmierer, aber das sollte leicht zuzuordnen sein):

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

}

Ich habe keine Implementierung bereitgestellt , aber Sie können die von @Jon vorgeschlagenen Methoden verwenden . Hier ist eine gute Diskussion, die Sie sich ansehen können.


0

Sie müssen nicht zwei Kriterien definieren, sondern können eines definieren und klonen. Zum Klonen von nHibernate-Kriterien können Sie einen einfachen Code verwenden:

var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.