2

我在Nhibernate 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子句并仅回退最近的状态更新,我需要对查询进行哪些更改?

感谢

回答

3

收集DIPEpisodeStatuss总是与所有实体初始化,因为它会破坏否则changetracking。你可以为集合定义一个过滤器或者用你想要的返回一个DTO。此外,由于无法在一个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>(); 
+0

完成或者我去修改返回的DTO的路线。我穿过每个epiodde dto,然后订购epsiode状态并查找第一条记录,然后将其设置为epsode状态集合。 – 2012-03-13 13:38:21

+0

这将加载所有stati或者是SELECT N + 1,其中N是Episode集合的计数 – Firo 2012-03-13 15:49:51