1

我有以下实体:

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,但包含实际班次或班次历史记录会很酷。

谢谢阅读。

4

4 回答 4

3
        var list = 
            this.Session.Query<Shift>().Select(
                p => new
                {
                    Shift = p,
                    LastShiftHistory =
                        this.Session.Query<ShiftHistory>()
                            .Where(sh => sh.Shift == p)
                            .OrderByDescending(sh => sh.ShiftEndLocal)
                            .Select(sh => sh)
                            .FirstOrDefault()
                })
                .ToList();

应该管用。投影到 DTO 会更好,因为子查询将延迟加载。

于 2013-01-31T19:50:41.330 回答
1

像这样的东西应该可以工作......你的结果是匿名类型,因为不同类的caluses组合......

   public class QueryPlace()
    {
        List<ShiftHistory> ShiftHistrys = new List<ShiftHistory>();
        List<Shift> Shifts = new List<Shift>();
        List<Zone> Zones = new List<Zone>();

        public object MakeQuery()
        {
            var mshift = (from r in (from sh in session.Query<ShiftHistory>() from sf in session.Query<Shift>() where sh.Shift == sf
                         select new{sh.ShiftStartLocal, sh.ShiftEndLocal, sf.ShiftId, sf.ShiftHistory}) group r by r.ShiftId into g
                        select new {ShiftStartLocal = g.Max(s => s.ShiftStartLocal), ShiftEndLocal = g.Max(s => s.ShiftEndLocal), ShiftId = g.Key}).FirstOrDefault();

            return mshift;
        }
    }
于 2013-02-01T10:10:50.120 回答
0

只是为了完整起见,因为我的这个数据库使用复合 ID,所以我无法获得提供的完整查询 gunteman。

我最终得到的是我的原始查询,用 NH 编写:

        var list =

        this.Session.Query<Shift>()
            .Select(
                p => 
                new ShiftScheduleResult()
                {
                    ShiftId =  p.ShiftId,
                    ShiftDesc = p.ShiftDesc,
                    LastShiftStartLocal
                        = p.ShiftHistory
                            .OrderByDescending(sh => sh.ShiftEndLocal)
                            .Select(x => x.ShiftStartLocal)
                            .FirstOrDefault(),
                    LastShiftEndLocal
                        = p.ShiftHistory
                            .OrderByDescending(sh => sh.ShiftEndLocal)
                            .Select(x => x.ShiftEndLocal)
                            .FirstOrDefault()
                })
            .ToList();

我相信 Zoran 的查询也会起作用。感谢大家的帮助。

于 2013-02-04T08:10:17.267 回答
-1

当DB方案结合业务需求导致查询复杂时,改变DB方案会更好。例如,在您的 ShiftHistory 上添加一个“活动”标志,或者在最后一个 ShiftHistory 上的 Shift 中添加一个外键。当然,这可以被视为某种“反规范化”,可能在 DB 中存在不连贯的数据(同一 Shift 的多个活动历史记录,或者“Last shift”外键未指向真正的最后一个)。但是处理这些风险会比维护一个复杂的查询花费更多吗?我认为这是一个权衡。

于 2013-02-01T08:53:23.740 回答