代码之家  ›  专栏  ›  技术社区  ›  moribvndvs

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

  •  13
  • moribvndvs  · 技术社区  · 16 年前

    我读过 this article

    • Collection with lazy=extra lazy extra表示NHibernate适应 可能运行的操作 blog.Posts.Count不会强制 而是创建一个select count(*) 来自BlogId=1的帖子 声明,还有 只产生一个查询,而不是 支付装载整个 收集到内存。
    • 寻呼!)在你的实体之上 收藏,这意味着你可以 轻松浏览blog.Posts 集合,而不必加载 把整件事都记在记忆里。

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

    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; }
    }
    

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

    我的测试用例如下所示:

            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=“额外” ,呼叫 b.Posts.Count 做什么 SELECT COUNT(Id)... b.Posts.Skip(0).Take(5) 只需获取Blog.Id=?Id的所有帖子,然后应用程序端的LINQ就可以从结果集合中获取前5个帖子。

    有什么好处?

    1 回复  |  直到 16 年前
        1
  •  9
  •   asgerhallas    16 年前

    您可以这样做分页(来自文档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方法那么顺利。我想他们以后也会加入语法的。