Я читаю эту статью, где Айенде утверждает, что NHibernate может (по сравнению с EF 4):
- Коллекция с lazy = "extra" - Lazy extra означает, что NHibernate приспосабливается к операции, которые вы могли бы запустить верхней части ваших коллекций. Это значит что blog.Posts.Count не заставит загрузка всей коллекции, но скорее, создаст "select count (*) от сообщений, где BlogId = 1" и что blog.Posts.Contains() будет аналогичным образом приводит к одному запросу, а не к платя цену за загрузку всего сбор в память.
- Фильтры коллекции и выложенные коллекции - это позволяет вам определить дополнительные фильтры (в том числе пейджинг!) поверх ваших объектов коллекции, что означает, что вы можете легко страницы через 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 = "extra" , вызов b.Posts.Count
делает SELECT COUNT(Id)...
, что отлично. Тем не менее, b.Posts.Skip(0).Take(5)
просто захватывает все сообщения для Blog.Id =? Id, а затем LINQ на стороне приложения просто берет первые 5 из результирующей коллекции.
Что дает?