Подзапрос NHibernate QueryOver возвращает только новейшую запись - PullRequest
2 голосов
/ 13 марта 2012

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

SQL для этого выглядит следующим образом:

SELECT  *
FROM    DIPEpisode e
INNER JOIN DIPEpisodeStatus s on s.EpisodeID = e.SequenceID
WHERE e.ClientID = '1000001'
AND s.SequenceID IN (
SELECT TOP 1 SequenceID
FROM DIPEpisodeStatus s
WHERE s.EpisodeID = e.SequenceID
ORDER BY StatusRecordedDate DESC
)

Я написал следующий запрос, который дает мне почти точно то, что мне нужно

var statuses =
            QueryOver.Of<DIPEpisodeStatus>()
            .OrderBy(x => x.StatusRecordedDate).Desc
            .Select(x => x.Id).Take(1);

DIPEpisodeStatus statusAlias = null;

        return
            session.QueryOver<DIPEpisode>()
            .JoinQueryOver(x => x.DIPEpisodeStatuss, () => statusAlias)
            .Fetch(x => x.AgencyID).Eager
            .Fetch(x => x.DIPEpisodeStatuss).Eager
            .Where(e => e.ClientID.Id == this.clientId)
            .WithSubquery.WhereProperty(x => x.Id).Eq(statuses)
            .List();

Это генерирует следующий SQL:

SELECT *
FROM   DIPEpisode this_
   inner join DIPEpisodeStatus statusalia1_
     on this_.SequenceID = statusalia1_.EpisodeID
WHERE  statusalia1_.ClientID = '1000001' /* @p0 */
   and statusalia1_.SequenceID = (SELECT TOP (1 /* @p1 */) this_0_.SequenceID as y0_
                                  FROM   DIPEpisodeStatus this_0_
                                  ORDER  BY this_0_.StatusRecordedDate desc)

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

Спасибо

Бен

1 Ответ

3 голосов
/ 13 марта 2012

коллекция DIPEpisodeStatuss всегда инициализируется со всеми сущностями, потому что в противном случае это может нарушить отслеживание изменений.Вы можете либо определить фильтр для коллекции, либо вернуть DTO с тем, что вы хотите.Также выборка будет игнорироваться, потому что она не может загружать и фильтровать в одном выражении SQL.

Здесь описаны фильтры NHibernate

определение фильтров в FNH

как это будет сделано с DTO

// assuming SequneceID and StatusRecordedDate correlates
var subquery = QueryOver.Of<DIPEpisode>()
        .Where(e => e.ClientID.Id == this.clientId)
        .JoinAlias(e => e.DIPEpisodeStatuss, () => statusAlias)
        .Select(Projections.Max(() => statusAlias.SequenceID));

// or as in question
var subquery = QueryOver.Of<DIPEpisode>()
        .Where(e => e.ClientID.Id == this.clientId)
        .JoinAlias(e => e.DIPEpisodeStatuss, () => statusAlias)
        .OrderByDescending(() => statusAlias.StatusRecordedDate)
        .Select(() => statusAlias.SequenceID)
        .Take(1);

DIPEpisodeDto dto = null;
DIPEpisodeStatus statusAlias = null;
return session.QueryOver<DIPEpisode>()
        .Where(e => e.ClientID.Id == this.clientId)
        .JoinQueryOver(e => e.DIPEpisodeStatuss, () => statusAlias)
        .WithSubquery.WhereProperty(estatus => estatus.Id).Eq(statuses)
        .SelectList(list => list
            .Select(e => e.Whatever).WithAlias(() => dto.Whatever)
            .Select(() => statusAlias.SquenceId).WithAlias(() => dto.StatusId)
            ...
        )
        .TransFormUsing(Transformers.AliasToBean<DIPEpisodeDto>())
        .List();

или с использованием LINQ

var query = from e in session.Query<DIPEpisode>()
            from s in e.DIPEpisodeStatuss
            where e.ClientID.Id == this.clientId
            where s.Id == (
                from e2 in session.Query<DIPEpisode>()
                from s2 in e2.DIPEpisodeStatuss
                orderby s2.StatusRecordedDate descending
                select s2.Id)
                .First()
            select new DIPEpisodeDto
            {
                e.Prop1,
                Status = s,
            };
return query.List<DIPEpisodeDto>();
...