Я прочитал эту статью, где Ayende заявляет, что NHibernate может (по сравнению с EF 4):
- Набор с ленивым =” дополнительный” – Ленивый дополнительный означает, что NHibernate адаптируется к операциям, которые Вы могли бы выполнить сверху своих наборов. Это означает тот блог. Сообщения. Количество не вызовет загрузку всего набора, а скорее создало бы “избранное количество (*) из Сообщений где BlogId = 1” оператор и тот блог. Сообщения. Содержит (), аналогично приведет к единому запросу вместо того, чтобы платить цену загрузки всего набора к памяти.
- Фильтры набора и разбитые на страницы наборы - это позволяет Вам определять дополнительные фильтры (включая подкачку страниц!) сверху Ваших наборов объектов, что означает, что можно легко пролистать блог. Набор сообщений, и не должен загрузить всю вещь в память.
Таким образом, я решил соединить тестовый сценарий. Я создал модель 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);
}
}
}
Используя ленивый = "дополнительный", вызов к b.Posts.Count
действительно делает a SELECT COUNT(Id)...
который является большим. Однако b.Posts.Skip(0).Take(5)
просто захваты все Сообщения для Блога. Идентификатор =? идентификатор и затем LINQ на стороне приложения просто берут первые 5 от получающегося набора.
Что дает?
Я почти уверен (читая комментарии), что он говорит о CreateFilter of ISession.
Вы можете делать разбиение по страницы следующим образом (из документов 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. Я думаю, что они тоже присоединятся к синтаксису через некоторое время.