使用NHibernate对延迟加载的集合进行分页

我读过这篇文章 ,其中Ayende表示NHibernate可以(与EF 4相比):

  • 使用lazy =“extra”的集合 – Lazy extra意味着NHibernate适应您可能在集合之上运行的操作。 这意味着blog.Posts.Count不会强制加载整个集合,而是会从Posts中创建一个“select count(*),其中BlogId = 1”语句,而blog.Posts.Contains()同样会产生在单个查询中,而不是支付将整个集合加载到内存的价格。
  • 集合filter和分页集合 – 这允许您在实体集合之上定义其他filter(包括分页!),这意味着您可以轻松浏览blog.Posts集合,而不必将整个内容加载到内存中。

所以我决定整理一个测试案例。 我创建了陈词滥调的Blog模型作为一个简单的演示,有两个类如下:

public class Blog { public virtual int Id { get; private set; } public virtual string Name { get; set; } public virtual ICollection Posts { get; private set; } public virtual void AddPost(Post item) { if (Posts == null) Posts = new List(); if (!Posts.Contains(item)) Posts.Add(item); } } public class Post { public virtual int Id { get; private set; } public virtual string Title { get; set; } public virtual string Body { get; set; } public virtual Blog Blog { get; private set; } } 

我的映射文件如下所示:

                                      

我的测试用例看起来像这样:

  using (ISession session = Configuration.Current.CreateSession()) // this class returns a custom ISession that represents either EF4 or NHibernate { blogs = (from b in session.Linq() where b.Name.Contains("Test") orderby b.Id select b); Console.WriteLine("# of Blogs containing 'Test': {0}", blogs.Count()); Console.WriteLine("Viewing the first 5 matching Blogs."); foreach (Blog b in blogs.Skip(0).Take(5)) { Console.WriteLine("Blog #{0} \"{1}\" has {2} Posts.", b.Id, b.Name, b.Posts.Count); Console.WriteLine("Viewing first 5 matching Posts."); foreach (Post p in b.Posts.Skip(0).Take(5)) { Console.WriteLine("Post #{0} \"{1}\" \"{2}\"", p.Id, p.Title, p.Body); } } } 

使用lazy =“extra” ,对b.Posts.Count的调用确实做了一个SELECT COUNT(Id)...这很棒。 但是, b.Posts.Skip(0).Take(5)只抓取Blog.Id =?id的所有post,然后应用程序端的LINQ只是从结果集合中获取前5个。

是什么赋予了?

我非常肯定(阅读评论)他正在谈论ISession的CreateFilter。

您可以像这样进行分页(来自文档13.13):

 Collections are pageable by using the IQuery interface with a filter: IQuery q = s.CreateFilter( collection, "" ); // the trivial filter q.setMaxResults(PageSize); q.setFirstResult(PageSize * pageNumber); IList page = q.List(); 

或者(来自文档17.1.4):

 s.CreateFilter( lazyCollection, "").SetFirstResult(0).SetMaxResults(10).List(); 

这不像使用System.Linq方法那么顺利。 我猜他们也会加入语法一段时间。