Как сделать выборку дочерних объектов из списка элементов? - PullRequest
1 голос
/ 27 марта 2012

У меня есть метод поиска, который возвращает несколько элементов, каждый из которых имеет несколько дочерних свойств со ссылками на другие таблицы. Для дочернего свойства, которое является коллекцией, все работает так, как я хочу, но как я могу сделать то же самое для детей один на один?

Вот некоторые заглушки и часть кода, который я пробовал:

public class Request {
    //HasMany(x => x.Examinations).Access.CamelCaseField().Cascade.All().BatchSize(100);
    public virtual IList<Examination> Examinations;

    //References(x => x.Creator, "rem_creator_userid");
    public virtual User Creator { get; private set; }
}

public class RepositoryExample {

    // This search will ask one nice-looking query to the database fetchning all the
    // requests
    // Then it will ask ONE query fetching the Examinations from the database
    // Then it will ask N+1 questions fetching Creator from all Requests
    public IList<Request> Search1(ListRequestSearchConditions searchConditions) {
        var query =
            from request in Session.Query<Request>()
            from exam in request.Examinations
            where
                searchConditions.Units.Contains(request.ReferralSource) &&
                exam.Status.HasValue &&
                exam.Status.Value >= ExaminationStatus.Value.RequestSubmitted &&
                request.PatientId != null
            select request;

        return query
            .Skip((searchConditions.Page - 1) * searchConditions.PageSize)
            .Take(searchConditions.PageSize)
            .ToList();
    }

    // This search with ask one slow join-query fetching everything from the database
    public IList<Request> Search2(ListRequestSearchConditions searchConditions) {
            Examination examinationAlias = null;

        return Session.QueryOver<Request>()
            .WhereRestrictionOn(request => request.ReferralSource).IsIn(searchConditions.Units)
            .Where(request => request.PatientId != null)
            .JoinAlias(request => request.Examinations, () => examinationAlias)
            .Where(() => examinationAlias.Status.Value != null)
            .Where(() => examinationAlias.Status.Value >= ExaminationStatus.Value.RequestSubmitted)
            .Skip((searchConditions.Page - 1) * searchConditions.PageSize)
            .Take(searchConditions.PageSize)
            .ToList();
    }

    // This search will first ask ONE query joining Request with Examinations
    // Then it will ask ONE query fetching the Examinations from the database
    // Then it will ask N+1 queries fetching Creator from all Requests
    public IList<Request> Search3(ListRequestSearchConditions searchConditions) {
            Examination examinationAlias = null;

        return Session.QueryOver<Request>()
            .WhereRestrictionOn(request => request.ReferralSource).IsIn(searchConditions.Units)
            .Where(request => request.PatientId != null)
            .JoinAlias(request => request.Examinations, () => examinationAlias)
            .Where(() => examinationAlias.Status.Value != null)
            .Where(() => examinationAlias.Status.Value >= ExaminationStatus.Value.RequestSubmitted)
            .Fetch(request => request.Examinations).Lazy
            .Fetch(request => examinationAlias.ExaminationType).Lazy;
            .Skip((searchConditions.Page - 1) * searchConditions.PageSize)
            .Take(searchConditions.PageSize)
            .ToList();
    }
}

Я надеюсь, что это можно сделать в 3 запросах, один для получения списка запросов, один для получения экзаменов и один для создателей.

Ответы [ 2 ]

1 голос
/ 27 марта 2012

Если вы не хотите использовать его в одном запросе (используя Fetch / ThenFetch в LINQ) и вместо этого используете пакетную обработку, вы должны указать его на уровне отображения Creator. Размер пакета не может быть определен на уровне запроса.

В Fluent NHibernate вы можете просто добавить BatchSize(100) в ваше Creator отображение.

0 голосов
/ 28 марта 2012

все в одну сторону

// determine the requests
var subquery = QueryOver.Of<Request>()
    .WhereRestrictionOn(request => request.ReferralSource).IsIn(searchConditions.Units)
    .Where(request => request.PatientId != null)
    .JoinQueryOver(request => request.Examinations)
    .Where(examination => examination.Status.Value != null)
    .Where(examination => examinationAlias.Status.Value >= ExaminationStatus.Value.RequestSubmitted)
    .Skip((searchConditions.Page - 1) * searchConditions.PageSize)
    .Take(searchConditions.PageSize)
    .Select(r => r.Id);

// load the requests with eagerly fetching the associations
var results = Session.QueryOver<Request>()
    .WithSubquery.WhereProperty(request => request.Id).In(subquery)
    .Fetch(request => request.Creator).Eager
    .Fetch(request => request.Examinations).Eager
    .ToList();
...