代码之家  ›  专栏  ›  技术社区  ›  Scott Stafford

如何分组/聚合但返回聚合字段以外的字段?

  •  1
  • Scott Stafford  · 技术社区  · 14 年前

    我有两个表,任务和任务里程碑。我希望查询返回每个任务最近的过去里程碑和最近的将来任务里程碑。我正在与C/Linq to SQL合作。我该怎么办?

    任务列:id,taskname 任务里程碑列:ID、任务ID、里程碑名称、里程碑日期

    我想要一个包含以下行的返回表:taskname、milestonedate、milestonename

    我当前的解决方案导致Linq为每个任务查询数据库一次,这是不可接受的缓慢。

    [编辑以解决注释]当前的实现很简单,不是一条语句,它只查询任务列表,然后使用适当的where子句对每个taskid查询两次:

    var x = from p in this.Database.Task
            join pm in this.Database.TaskMilestones on p.Id equals pm.TaskId
            select new
            {
                TaskId = p.Id,
                TaskName = p.Name,
                MilestoneName = m.Name,
                MilestoneDate = pm.MilestoneDate,
            };
    
    foreach (var record in records)
    {
        var y = x.Where(p => p.TaskId == record.Id && p.MilestoneDate <= dt);
        var z = x.Where(p => p.TaskId == record.Id && p.MilestoneDate > dt);
    
        ...
    
    2 回复  |  直到 14 年前
        1
  •  1
  •   Amy B    14 年前
    DateTime dt = DateTime.Today;
    
    var records =
      from p in db.Tasks
      let pastMilestone = p.TaskMilestones
        .Where(pm => pm.MilestoneDate <= dt)
        .OrderByDescending(pm => pm.MilestoneDate)
        .FirstOrDefault()
      let nextMilestone = p.TaskMilestones
        .Where(pm => pm.MilestoneDate > dt)
        .OrderBy(pm => pm.MilestoneDate)
        .FirstOrDefault()
      select new
      {
        Task = p,
        PastMilestone = pastMilestone,
        NextMilestone = nextMilestone
      }
    

    另一种选择是加载每个项目的所有里程碑,然后使用LinqtoObjects进行筛选:

    DataLoadOptions dlo = new DataLoadOptions();
    dlo.LoadWith<Task>(p => p.TaskMilestones);
    db.LoadOptions = dlo;
    
    var records = db.Tasks;
    
    foreach(Task record in records)
    {
      TaskMilestone pastMilestone = record.TaskMilestones
            .Where(pm => pm.MilestoneDate <= dt)
            .OrderByDescending(pm => pm.MilestoneDate)
            .FirstOrDefault()
      TaskMilestone nextMilestone = record.TaskMilestones
            .Where(pm => pm.MilestoneDate > dt)
            .OrderBy(pm => pm.MilestoneDate)
            .FirstOrDefault()
    }
    
        2
  •  0
  •   Craig Stuntz    14 年前

    在我的头顶上:

    var q = from t in Context.Tasks
            let mostRecentDate = t.Milestones.Where(m => m.MilestoneDate < DateTime.Now)
                                             .Max(m => m.MilestoneDate)
            select new 
            {
                TaskId = t.Id,
                TaskName = t.TaskName,
                RecentPastMilestone = t.Milestones.Where(m => m.MilestoneDate == mostRecentDate)
                                                  .FirstOrDefault()
            };