Как получить 20 лучших родительских объектов со всеми дочерними для каждого объекта - PullRequest
0 голосов
/ 04 октября 2011

У меня есть общий корень, который является WallPost. WallPost может иметь от нуля до многих WallPostComments.

Я хочу написать запрос для получения 20 сообщений на стене (по заказу DateCreated по убыванию), а также с нетерпением получить все комментарии для этих 20 сообщений на стене.

Я пытался использовать NHibernate Linq и предложение Fetch (), но это приводит к «firstResult / maxResults, указанному при получении коллекции; применение в памяти!» ошибка.

Два других подхода, которые я пробовал:

var wallPostQuery = _session.QueryOver<WallPost>()
            .Where(x => x.WallId == wallId)
            .OrderBy(x => x.DateCreated)
            .Desc
            .Left.JoinQueryOver(x => x.Comments)
            .Take(20)
            .Future<WallPost>();

Но, неожиданный сюрприз (ну, не совсем), это возвращает двадцать сообщений на стене с нулем или одним комментарием каждый. Я получаю дубликаты на стене, а это не то, чего я хочу.

Лучший запрос -

var wallPostQuery = _session.QueryOver<WallPost>().Where(x => x.WallId == wallId).OrderBy(x => x.DateCreated).Desc.Take(20).Future<WallPost>();

_session.QueryOver<WallPost>().Where(x => x.WallId == wallId).Left.JoinQueryOver(x => x.Comments).Future<WallPost>();

var wallPosts = wallPostQuery.ToList();

Это дает мне 20 сообщений на стене со связанными с ними комментариями, но запрос выполняется в виде двух вариантов выбора, когда второй элемент выбора объединяет WallPost с WallPostComment, эффективно вытягивая все сообщений и комментариев на стене (фильтруется только WallPostId). Это прекрасно работает, когда сообщений немного, но я не могу себе представить, насколько хорошо это масштабируется.

Должен быть лучший способ - но я не могу понять это. Есть предложения?

1 Ответ

1 голос
/ 04 октября 2011

Я думаю, что решение , которое я нашел для аналогичной (немного более сложной) проблемы, может вам помочь.
что-то вроде:

var wallPostIdsQuery = _session.QueryOver<WallPost>().Where(x => x.WallId == wallId).OrderBy(x => x.DateCreated).Desc.Take(20).Future<WallPost>()
.Select(p => p.Id);

var wallPostsQuery = _session.QueryOver<WallPost>().WithSubquery.WhereProperty(p => p.Id).In(wallPostIdsQuery);

var commentsQuery = _session.QueryOver<WallPostComment>().WithSubquery.WhereProperty(p => p.WallPostId).In(wallPostIdsQuery);

if (wallPostsQuery.Count() == 0)
{
  return wallPostsQuery.List();
}

NHibernateUtil.Initialize(wallPostsQuery.First().Comments);

или, возможно, только эти две строки -

var wallPostQuery = _session.QueryOver<WallPost>().Where(x => x.WallId == wallId).OrderBy(x => x.DateCreated).Desc.Take(20).Future<WallPost>();
NHibernateUtil.Initialize(wallPostQuery.First().Comments);

важно помнить, что необходимо сопоставить коллекцию комментариев со стратегией выборки 'subselect'.

...