使用 NHibernate 对延迟加载的集合进行分页 [英] Paging over a lazy-loaded collection with NHibernate

查看:18
本文介绍了使用 NHibernate 对延迟加载的集合进行分页的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I read this article where Ayende states NHibernate can (compared to EF 4):

  • Collection with lazy="extra" – Lazy extra 意味着 NHibernate 适应您可能运行的操作您收藏的顶部.这意味着那 blog.Posts.Count 不会强制整个集合的负载,但是而是创建一个选择计数(*)来自博客 ID = 1 的帖子"声明,并且blog.Posts.Contains() 同样会导致单个查询而不是支付整个加载的代价收集到内存.
  • 集合过滤器和分页集合 - 这允许您定义额外的过滤器(包括分页!)在您的实体之上集合,这意味着您可以轻松翻阅博客.帖子集合,而不必加载整个事情都变成了记忆.

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

So I decided to put together a test case. I created the cliché Blog model as a simple demonstration, with two classes as follows:

public class Blog
{
    public virtual int Id { get; private set;  }
    public virtual string Name { get; set; }

    public virtual ICollection<Post> Posts { get; private set;  }

    public virtual void AddPost(Post item)
    {
        if (Posts == null) Posts = new List<Post>();
        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; }
}

我的映射文件如下所示:

My mappings files look like this:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="Model.Blog, TestEntityFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Blogs">
    <id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <property name="Name" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Name" />
    </property>
    <property name="Type" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Type" />
    </property>
    <bag lazy="extra" name="Posts">
      <key>
        <column name="Blog_Id" />
      </key>
      <one-to-many class="Model.Post, TestEntityFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </bag>
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" name="Model.Post, TestEntityFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Posts">
    <id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <property name="Title" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Title" />
    </property>
    <property name="Body" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Body" />
    </property>
    <many-to-one class="Model.Blog, TestEntityFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Blog">
      <column name="Blog_id" />
    </many-to-one>
  </class>
</hibernate-mapping>

我的测试用例如下所示:

My test case looks something like this:

        using (ISession session = Configuration.Current.CreateSession()) // this class returns a custom ISession that represents either EF4 or NHibernate
        {
            blogs = (from b in session.Linq<Blog>()
                         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) 只是抓取所有的 Posts for Blog.Id = ?id,然后应用程序端的 LINQ 只是从结果中取出前 5 个收藏.

Using lazy="extra", the call to b.Posts.Count does do a SELECT COUNT(Id)... which is great. However, b.Posts.Skip(0).Take(5) just grabs all Posts for Blog.Id = ?id, and then LINQ on the application side is just taking the first 5 from the resulting collection.

是什么?

推荐答案

我很确定(阅读评论)他在谈论 ISession 的 CreateFilter.

I'm pretty sure (reading the comments) that he's talking about the CreateFilter of ISession.

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

You can do paging like this (from the docs 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):

Or (from the docs 17.1.4):

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

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

That's is not as smooth as using the System.Linq methods. I guess they'll join the syntax some time too.

这篇关于使用 NHibernate 对延迟加载的集合进行分页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆