Linq获取列表(父级)中的元素,其中条件满足子列表中对象的属性?

时间:2011-06-17 16:04:55

标签: linq

我想知道是否有人可以帮助我为以下场景生成linq查询。

以下是具有相关属性的类:

public class Employee 
{
    IList<Employee> DirectReports { get; set;}
    IList<BonusPlan> BonusPlans { get; set;}

    BonusPlanTemplate BonusPlanTemplate { get; set;}
}

public class BonusPlan
{
    FiscalPeriod FiscalPeriod { get; set; }
    Employee Employee { get; set;}
}

我正在尝试创建一个方法:

IEnumerable<Employee> GetDirectReportsWithoutBonusPlansCreatedForFiscalPeriod(FiscalPeriod fiscalPeriod)

所以基本上我有这个来获得特定财政期间奖金计划的直接报告:

var query = from dr in DirectReports
            from bp in dr.BonusPlans
            where bp.Employee.BonusPlanTemplate != BonusPlanTemplate.Empty && 
              bp.FiscalPeriod==fiscalPeriod
            select dr;

IList<Employee> directReportsWithBonusPlansCreated = query.ToList();

然后我得到所有应该有奖励计划设置的DirectReports(通过分配BonusPlanTemplate表示),这些不在上一个查询的列表中。

var query2 = from dr in DirectReports
             where dr.BonusPlanTemplate != BonusPlanTemplate.Empty &&
                !directReportsWithBonusPlansCreated.Contains(dr)
             select dr;

这会产生正确的结果,但似乎必须有另一种方式。我不确定是否需要分两步完成。有人可以帮我组合这两个linq查询,并可能使它更有效。我对Linq的经验相对较少。

2 个答案:

答案 0 :(得分:3)

您是否因任何其他原因需要第一个查询?如果没有,那很简单:

var query = from dr in DirectReports
            where dr.BonusPlanTemplate != BonusPlanTemplate.Empty
               && !dr.BonusPlans.Any(bp => bp.FiscalPeriod == fiscalPeriod)
            select dr;

您可以在Employee中使用额外的方法让您的生活更轻松:

public bool HasBonusPlanForPeriod(FiscalPeriod period)
{
    return BonusPlans.Any(bp => bp.FiscalPeriod == fiscalPeriod);
}

然后您的原始第一个查询变为:

var query = from dr in DirectReports
            where dr.BonusPlanTemplate != BonusPlanTemplate.Empty && 
                  dr.HasBonusPlanForPeriod(fiscalPeriod)
            select dr;

IList<Employee> directReportsWithBonusPlansCreated = query.ToList();

,第二个查询变为:

var query = from dr in DirectReports
            where dr.BonusPlanTemplate != BonusPlanTemplate.Empty && 
                  !dr.HasBonusPlanForPeriod(fiscalPeriod)
            select dr;

IList<Employee> directReportsWithBonusPlansCreated = query.ToList();

答案 1 :(得分:1)

这是一个棘手的问题......首先我想“哦,这是一个外部联接......使用DefaultIfEmpty”。然后我意识到你正在做一些选择(这是从条款归结为两个)。所以我搜索了与SelectMany和came up with this gem结合使用的DefaultIfEmpty。应用于您的场景我们得到

var query = 
  from dr in DirectReports              
  from bp in dr.BonusPlans.DefaultIfEmpty()

  where dr.BonusPlanTemplate != BonusPlanTemplate.Empty && 
  bp.FiscalPeriod==fiscalPeriod &&
  bp==null
  select dr; 

看看它是否适合你。