2010-06-21 46 views
1

我有两个表,任务和TaskMilestones。我想要查询返回每个任务的最近过去的里程碑和最近的未来TaskMilestone。我正在使用C#/ LINQ到SQL。我如何去做这件事?如何分组/聚合但返回汇总字段以外的字段?

任务栏:ID,TASKNAME TaskMilestones列:ID,任务id,MilestoneName,MilestoneDate

我想与含有行的返回表:TASKNAME,MilestoneDate,MilestoneName

我目前的解决方案导致的LINQ查询每个任务的数据库一次,这是无法接受的缓慢。

[编辑处理意见]当前的实现很简单,不是一个单一的语句,而只是用适当的where子句查询任务列表,然后为每个任务id查询两次:

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

    ... 
+1

也许将您当前的解决方案添加到该帖子中? – Andomar 2010-06-21 16:54:04

+0

+1,我也有兴趣看到你目前的LINQ。 – VoodooChild 2010-06-21 17:13:13

回答

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 
    } 

另一种选择是加载所有的里程碑为电子ach项目,然后使用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() 
} 
+0

谢谢,第一个工作正常。我将PastMilestone字段更改为几个单独的字段,但以其他方式逐字使用。 – 2010-06-21 17:53:39

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

我刚刚尝试过,但它会导致Linq生成多个SQL查询。其中一个任务: SELECT TOP(1)[t0]。[Id],[t0]。[NeedDate],[t0]。[Duration],[t0]。[IsShown],[t0]。[ ProgramOn],[t0]。[MilestonesId],[t0]。[StatusId],[t0]。[CreatedOn],[t0]。[ModifiedOn],[t0]。[CreatedBy],[t0]。[ModifiedBy] ,[t0]。[ActualCompletion] FROM [ProgramsMilestones] AS [t0] WHERE([t0]。[NeedDate] = @ x2)AND([t0]。[ProgramId] = @ x1)GO – 2010-06-21 17:29:45

+0

奇数。它不在L2E中。虽然它会比你拥有的还要快,但它并不理想。我会考虑一下。 – 2010-06-21 17:32:40

+0

你可以尝试将'let'合并到'select'部分。我并不真正了解L2S关于SQL生成的确切规则,但它值得一试。 – 2010-06-21 17:35:19