NHibernate QueryOver子查询只返回最新记录

时间:2012-03-13 09:34:33

标签: nhibernate fluent-nhibernate subquery queryover

我在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子句。我需要对查询进行哪些更改才能生成此额外的where子句并仅撤回最新的状态更新?

由于

1 个答案:

答案 0 :(得分:3)

集合DIPEpisodeStatuss始终使用所有实体进行初始化,否则会破坏更改跟踪。您可以为集合定义过滤器,也可以根据需要返回DTO。此外,fetch将被忽略,因为它无法在一个sql语句中加载和过滤。

NHibernate filters are explained here

defining Filters in 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>();