Как можно пейджинговать с помощью NHibernate?

107

Например, я хочу заполнить элемент управления gridview на веб-странице ASP.NET только данными, необходимыми для # отображаемых строк. Как NHibernate может это поддерживать?

Луч
источник

Ответы:

111

ICriteriaимеет SetFirstResult(int i)метод, который указывает индекс первого элемента, который вы хотите получить (в основном первая строка данных на вашей странице).

У него также есть SetMaxResults(int i)метод, который указывает количество строк, которые вы хотите получить (т. Е. Размер вашей страницы).

Например, этот объект критериев получает первые 10 результатов вашей сетки данных:

criteria.SetFirstResult(0).SetMaxResults(10);
Джон Лимджап
источник
1
В любом случае синтаксис Linq (to NH) будет выглядеть примерно так - красиво.
MotoWilliams,
13
Важно отметить, что вам нужно будет выполнить отдельную транзакцию для получения общего количества строк, чтобы отобразить ваш пейджер.
Кевин Панг,
1
Это выполняет запрос SELECT TOP в SQL Server. Попробуйте использовать SetFirstResult (1) .SetMaxResult (2);
Крис С.
4
Этот предыдущий комментарий использует NHibernate.Dialect.MsSql2000Dialect, а не NHibernate.Dialect.MsSql2005Dialect
Крис С.
IQuery имеет те же функции, поэтому его можно использовать и с HQL.
goku_da_master
87

Вы также можете воспользоваться функцией Futures в NHibernate для выполнения запроса, чтобы получить общее количество записей, а также фактические результаты в одном запросе.

пример

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

Чтобы получить общее количество записей, сделайте следующее:

int iRowCount = rowCount.Value;

Хорошее обсуждение того, что дает вам Futures, здесь .

Джереми Д.
источник
3
Это круто. Futures работает точно так же, как и многокритериальные, без синтаксической сложности многокритериальной.
DavGarcia
После прочтения поста о Futures я задаюсь вопросом, следует ли мне использовать Future для всех моих запросов к базе данных ... В чем недостаток? :)
hakksor
46

Начиная с NHibernate 3 и выше, вы можете использовать QueryOver<T>:

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

Вы также можете явно упорядочить свои результаты следующим образом:

var pageRecords = nhSession.QueryOver<TEntity>()
            .OrderBy(t => t.AnOrderFieldLikeDate).Desc
            .Skip((PageNumber - 1) * PageSize)
            .Take(PageSize)
            .List();
Леандро де лос Сантос
источник
.Skip(PageNumber * PageSize)таким образом, если размер страницы равен 10, первые 10 строк никогда не будут получены. Я редактирую, чтобы формула была правильной. Предполагая, что концептуально PageNumberне должно быть 0. Это должно быть минимум 1.
Амит Джоши
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); }
      }

Есть ли другой способ получить типизированный результат из MultiCriteria при разбиении на страницы данных, или все делают то же самое, как и я?

Спасибо

Барбарос Альп
источник
23

Как насчет использования Linq для NHibernate, как описано в этой записи блога Айенде?

Пример кода:

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

А вот подробный пост в блоге команды NHibernate о доступе к данным с помощью NHibernate, включая реализацию разбиения на страницы.

NotMyself
источник
Обратите внимание, что linq to Nhibernate находится в пакете contrib и не включен в выпуск NHibernate 2.0
Ричард
11

Скорее всего, в GridView вы захотите отобразить фрагмент данных плюс общее количество строк (rowcount) от общего объема данных, соответствующих вашему запросу.

Вы должны использовать MultiQuery для отправки запросов Select count (*) и .SetFirstResult (n) .SetMaxResult (m) в вашу базу данных за один вызов.

Обратите внимание, что результатом будет список, содержащий 2 списка: один для среза данных, а другой - для подсчета.

Пример:

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

Я предлагаю вам создать определенную структуру для разбивки на страницы. Что-то вроде (я программист на Java, но это должно быть легко сопоставить):

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

}

Я не предлагал реализацию, но вы можете использовать методы, предложенные @Jon . Вот вам хорошее обсуждение .

Марсио Агиар
источник
0

Вам не нужно определять 2 критерия, вы можете определить один и клонировать его. Чтобы клонировать критерии nHibernate, вы можете использовать простой код:

var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();
Марчин
источник