我有以下实体:
public class Shift
{
public virtual int ShiftId { get; set; }
public virtual string ShiftDesc { get; set; }
public virtual IList<ShiftHistory> ShiftHistory { get; set; }
}
public class ShiftHistory
{
public virtual System.DateTime ShiftStartLocal { get; set; }
public virtual System.DateTime ShiftEndLocal { get; set; }
public virtual Zone Zone { get; set; }
public virtual Shift Shift { get; set; }
public virtual int RowId { get; set; }
}
public class Zone
{
public virtual int EntId { get; set; }
public virtual string EntName { get; set; }
}
班次是一个班次定义,区域是人们工作的地方,而班次历史是在某个区域运行班次的历史数据。
我需要的是最后一次为所有区域运行班次。
/* 编辑:对不起,我含糊其辞。每个班次都可以有多个区域的历史记录。我需要的是任何 NH 查询类型中的最新历史记录,无论该区域如何,每次班次。*/
但这并不是那么简单,至少现在对我来说不是,而且我在这上面花了太多时间,最后还是求助于做一个 sql 查询:
public class GetAllShiftSchedules : AbstractQueryObject<IList<ShiftScheduleResult>>
{
public override IList<ShiftScheduleResult> GetResult()
{
//use distinct because of the zones - if a shift is run at multiple zones, it ends at the same time, no? :)
var sql =
@"
select distinct
sh.ShiftId, s.ShiftDesc, sh.ShiftStartLocal, sh_inner.LatestEndTimeLocal
from ShiftHistory sh
inner join Shift s on s.ShiftId = sh.ShiftId
inner join
(
select ShiftId, max(ShiftEndLocal) as LatestEndTimeLocal from ShiftHistory group by ShiftId
)
sh_inner on sh_inner.ShiftId = sh.ShiftId and sh_inner.LatestEndTimeLocal = sh.ShiftEndLocal
";
var res = this.Session.CreateSQLQuery(sql).List().OfType<object[]>().Select(p => new ShiftScheduleResult(p)).ToList();
return res;
}
}
public class ShiftScheduleResult
{
public int ShiftId { get; private set; }
public string ShiftDesc { get; private set; }
public DateTime LastShiftStartLocal { get; private set; }
public DateTime LastShiftEndLocal { get; private set; }
internal ShiftScheduleResult(object[] data)
{
this.ShiftId = (int)data[0];
this.ShiftDesc = (string)data[1];
this.LastShiftStartLocal = (DateTime)data[2];
this.LastShiftEndLocal = (DateTime)data[3];
}
}
我得到的最接近的是:
var innerSubquery =
QueryOver.Of<ShiftHistory>()
.Select(
Projections.Group<ShiftHistory>(e => e.Shift),
Projections.Max<ShiftHistory>(e => e.ShiftEndLocal));
IList<Shift> shifts =
this.Session.QueryOver<Shift>()
.JoinQueryOver<ShiftHistory>(p => p.ShiftHistory)
.Where(Subqueries.WhereProperty<ShiftHistory>(p => p.ShiftEndLocal).Eq(innerSubquery)).List();
其中生成了以下sql:
SELECT
...
FROM
Shift this_
inner join ShiftHistory shifthisto1_ on this_.ShiftId=shifthisto1_.ShiftId
WHERE
shifthisto1_.ShiftEndLocal =
(
SELECT this_0_.ShiftId as y0_, max(this_0_.ShiftEndLocal) as y1_ FROM ShiftHistory this_0_ GROUP BY this_0_.ShiftId
)
这当然会失败,因为 select 分组返回多个值,我们无法将其与 ShEndLoc 进行比较。如果我能让分组投影只返回最大日期,这实际上对我有用。但是,为了使其完整,我们还应该能够通过 shift id 进行比较。
我可以返回 DTO,但包含实际班次或班次历史记录会很酷。
谢谢阅读。