Làm thế nào bạn có thể phân trang với NHibernate?


107

Ví dụ: tôi muốn điền điều khiển gridview trong trang web ASP.NET chỉ với dữ liệu cần thiết cho # hàng được hiển thị. NHibernate có thể hỗ trợ điều này như thế nào?

Câu trả lời:


111

ICriteriacó một SetFirstResult(int i)phương thức, cho biết chỉ mục của mục đầu tiên mà bạn muốn lấy (về cơ bản là hàng dữ liệu đầu tiên trong trang của bạn).

Nó cũng có một SetMaxResults(int i)phương thức, cho biết số hàng bạn muốn lấy (tức là kích thước trang của bạn).

Ví dụ: đối tượng tiêu chí này nhận 10 kết quả đầu tiên của lưới dữ liệu của bạn:

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

1
Dù sao thì đây cũng giống như cú pháp Linq (tới NH) - Đẹp.
MotoWilliams 17/09/08

13
Điều quan trọng cần lưu ý là bạn sẽ cần thực hiện một giao dịch riêng để truy xuất tổng số hàng để hiển thị máy nhắn tin của bạn.
Kevin Pang

1
Điều này thực hiện một truy vấn CHỌN ĐẦU trong SQL Server. Hãy thử nó với SetFirstResult (1) .SetMaxResult (2);
Chris S

4
Đó là lời nhận xét trước đó được sử dụng NHibernate.Dialect.MsSql2000Dialect không NHibernate.Dialect.MsSql2005Dialect
Chris S

IQuery có các chức năng tương tự, vì vậy nó cũng có thể được sử dụng với HQL.
goku_da_master

87

Bạn cũng có thể tận dụng tính năng Futures trong NHibernate để thực hiện truy vấn nhằm lấy tổng số bản ghi cũng như kết quả thực tế trong một truy vấn duy nhất.

Thí dụ

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

Để có tổng số bản ghi, bạn làm như sau:

int iRowCount = rowCount.Value;

Một cuộc thảo luận tốt về những gì Futures cung cấp cho bạn ở đây .


3
Điều đó thật tuyệt. Tương lai hoạt động chính xác như đa tiêu chí mà không có sự phức tạp về cú pháp của đa tiêu chí.
DavGarcia

Sau khi đọc bài đăng về Futures, tôi tự hỏi liệu mình có nên sử dụng Future cho tất cả các truy vấn cơ sở dữ liệu của mình không ... Hạn chế là gì? :)
hakksor

46

Từ NHibernate 3 trở lên, bạn có thể sử dụng QueryOver<T>:

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

Bạn cũng có thể muốn sắp xếp các kết quả của mình một cách rõ ràng như thế này:

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

.Skip(PageNumber * PageSize)theo cách này, nếu kích thước trang là 10, nó sẽ không bao giờ truy xuất 10 hàng đầu tiên. Tôi đang chỉnh sửa để làm cho công thức chính xác. Giả sử rằng khái niệm, PageNumberkhông nên 0. Nó tối thiểu phải đạt 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); }
      }

Khi phân trang dữ liệu có cách nào khác để nhận được kết quả đã nhập từ MultiCriteria hay mọi người cũng làm như tôi không?

Cảm ơn


23

Làm thế nào về việc sử dụng Linq để NHibernate như được thảo luận trong bài đăng trên blog này của Ayende?

Mẫu mã:

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

Và đây là một bài đăng chi tiết của blog nhóm NHibernate về Truy cập dữ liệu Với NHibernate bao gồm cả việc triển khai phân trang.


Lưu ý linq to Nhibernate nằm trong gói đóng góp và không có trong bản phát hành NHibernate 2.0
Richard

11

Nhiều khả năng trong GridView, bạn sẽ muốn hiển thị một phần dữ liệu cộng với tổng số hàng (rowcount) của tổng lượng dữ liệu phù hợp với truy vấn của bạn.

Bạn nên sử dụng MultiQuery để gửi cả truy vấn Select count (*) và .SetFirstResult (n) .SetMaxResult (m) đến cơ sở dữ liệu của bạn trong một lần gọi.

Lưu ý rằng kết quả sẽ là một danh sách chứa 2 danh sách, một cho lát dữ liệu và một cho số lượng.

Thí dụ:

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

Tôi khuyên bạn nên tạo một cấu trúc cụ thể để đối phó với việc phân trang. Một cái gì đó như (Tôi là một lập trình viên Java, nhưng điều đó sẽ dễ dàng để lập bản đồ):

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

}

Tôi không cung cấp cách triển khai, nhưng bạn có thể sử dụng các phương pháp do @Jon đề xuất . Đây là một cuộc thảo luận tốt để bạn có thể xem qua.


0

Bạn không cần phải xác định 2 tiêu chí, bạn có thể xác định một và sao chép nó. Để sao chép các tiêu chí nHibernate, bạn có thể sử dụng một mã đơn giản:

var criteria = ... (your criteria initializations)...;
var countCrit = (ICriteria)criteria.Clone();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.