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

时间:2010-06-21 16:53:01

标签: sql linq linq-to-sql

我有两个表,Tasks和TaskMilestones。我想要一个查询来返回每个任务的最近的里程碑和最近的未来任务。我正在使用C#/ LINQ-to-SQL。我该怎么做?

任务列:Id,TaskName TaskMilestones列:Id,TaskId,MilestoneName,MilestoneDate

我想要一个包含以下行的返回表:TaskName,MilestoneDate,MilestoneName

我当前的解决方案会导致Linq为每个任务查询一次数据库,这速度慢得令人无法接受。

[EDIT来解决注释]当前的实现很简单而不是单个语句,它只查询任务列表,然后用适当的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 个答案:

答案 0 :(得分:1)

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()
}

答案 1 :(得分:0)

脱离我的头顶:

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()
        };