2

首先让我说我已经在这里搜索并阅读了很多关于动态 where 子句的线程,以及 ScottGu 的博客和 Albahari 的 PredicateBuilder 类,但我不确定如何正确应用这些方法中的任何一个我的情况。不知何故,我无法绕过它。

我有以下代码,当像这样“静态”完成时,它可以工作:

var persons = from father in fathers
              select new                                
              {
                 Count = father.Sons
                                    .Select(son => son)
                                    .Where(son => son.Skills.Any(skill => skill.SkillType == "Languages" && skill.Name == "French"))
                                    .Where(son => son.Skills.Any(skill => skill.SkillType == "Sport" && skill.Name == "Football"))
                                    .Count(),

                 Name = father.Name
               };

但是,我希望在运行时生成 where 子句。一个父亲对象有一个儿子对象的集合,而儿子对象又具有一个技能对象的集合。如查询所示,我想知道每个父亲的姓名以及他们拥有一定技能的儿子的数量。这组技能将在运行时选择,因此即使在示例中,我们只有两组技能(2 个 where 子句),它可以是 10 个或运行时任意数量的子句。

我认为我最大的问题是我似乎无法根据我的情况调整 StackOverflow 上给出的答案示例,因为我需要从顶层(父亲)获取信息以及来自第 3 层的信息(技能) 与第 2 级(儿子)的信息有关。

如果需要,我将在明天发布我已经尝试过的示例代码。我现在做不到,因为我有点着急。任何帮助将不胜感激。

编辑:

我需要的是一种在运行时连接 where 子句的方法,具体取决于用户选择了多少过滤条件。不同的过滤条件是从外部来源获得并在运行时构建的。例如:

在场景一中,可能有 3 个标准,例如用户选择的标准 1、标准 2 和标准 3。场景 2 可能有 5 个标准,例如标准 1、标准 2、...、标准 5。第三种情况可能有 10 个标准,例如标准 1、标准 2、...、标准 10。我需要的是能够为每个场景执行以下操作,而无需事先知道是否会有 3、5、10 或任何标准。

场景一:

var persons = from father in fathers
              select new                                
              {
                 Count = father.Sons
                                    .Select(son => son)
                                    .Where(criteria1)
                                    .Where(criteria2)
                                    .Where(criteria3)
                                    .Count(),

                 Name = father.Name
               };

场景二:

var persons = from father in fathers
              select new                                
              {
                 Count = father.Sons
                                    .Select(son => son)
                                    .Where(criteria1)
                                    .Where(criteria2)
                                    .Where(criteria3)
                                    .Where(criteria4)
                                    .Where(criteria5)
                                    .Count(),

                 Name = father.Name
               };

场景 3:

var persons = from father in fathers
                  select new                                
                  {
                     Count = father.Sons
                                        .Select(son => son)
                                      .Where(criteria1)
                      .Where(criteria2)
                      .Where(criteria3)
                      .Where(criteria4)
                      .Where(criteria5)                   
                      .Where(criteria6)
                      .Where(criteria7)
                      .Where(criteria8)
                      .Where(criteria9)
                      .Where(criteria10)
                                  .Count(),
                     Name = father.Name
                   };
4

3 回答 3

2

jonnyGold 的答案很好,但它要求 Son 对象具有对父亲对象的引用。这是一个不需要的解决方案:

var query = from father in fathers
            from son in father.Sons
            select new {father, son};

foreach (Skill skillCriterion in CriterionSkills)
{
    var capturedSkillCriterion = skillCriterion;
    query = query.Where(fs => fs.son.Skills.Any(
        skill => skill.SkillType == capturedSkillCriterion.SkillType && 
                 skill.Name == capturedSkillCriterion.Name));         
}         

var persons = from fs in query
              group fs by fs.father into g 
              select new                                 
              { 
                 Count = g.Count(),
                 Name = g.Key.Name
              };
于 2012-06-08T11:32:12.487 回答
1
var sons = fathers.SelectMany(f => f.Sons);

foreach(Skill skillCriterion in CriterionSkills)
{
    sons = sons.Where(son => son.Skills.Any(skill => skill.SkillType == skillCriterion.SkillType && skill.Name == skillCriterion.Name));
}

// we need to assume some sort of formal father-son relationship
var persons = from son in sons
              group son by new {son.Father.ID, son.Father.Name} into g
              select new
              {
                g.Key.Name,
                g.Count()
              };
于 2012-06-07T16:23:57.147 回答
0

然后设计您的查询来处理过滤器的动态特性。例如,我创建了父亲和儿子,儿子可以踢足球或排球。现在我的查询将采用仅说足球的动态请求......这是我的做法:

void Main()
{
   bool findFootballers   = true;
   bool findVolleyBallers = false;

   var Fathers = new List<Father>()
   {
      new Father() { Name = "Frank SR", Sons = new List<Son>() { new Son() { Name = "Bob", PlaysFootball = true }, new Son() { Name = "Frank", PlaysVolleyBall = true } } },
      new Father() { Name = "Knute", Sons = new List<Son>() { new Son() { Name = "Mean Jo Green", PlaysFootball = true }, new Son() { Name = "McMann", PlaysFootball = true } } }
   };


   Fathers.Where (f => (findFootballers == false) ? true : f.Sons.Any (s => s.PlaysFootball == true))
          .Where (f => (findVolleyBallers == false) ? true : f.Sons.Any (s => s.PlaysVolleyBall == true))
          .Select( f => new
                       {
                       Name = f.Name,
                       TargetSportSons = string.Join(", ", f.Sons
                                                            .Where (s => (findFootballers == false) ? true : s.PlaysFootball)
                                                            .Where (s => (findVolleyBallers == false) ? true : s.PlaysVolleyBall)
                                                            .Select (s => s.Name))
                       }
                 )
            .ToList()
            .ForEach(fs => Console.WriteLine ("Father {0} has these sons {1} who play {2}", fs.Name, fs.TargetSportSons, (findFootballers ? "Football" : "VolleyBall ")));

// Output
// Father Frank SR has these sons Bob who play Football
// Father Knute has these sons Mean Jo Green, McMann who play Football

}

public class Son
{
   public string Name { get; set; }
   public bool PlaysFootball { get; set; }
   public bool PlaysVolleyBall { get; set;}
}


public class Father
{
   public string Name { get; set; }
   public List<Son> Sons = new List<Son>();

}

// Define other methods and classes here
于 2012-06-07T16:46:29.320 回答