Linq 多级动态 where 子句
本文关键字:子句 where 动态 多级 Linq | 更新日期: 2023-09-27 18:36:39
,我要说的是,我已经在这里搜索并阅读了很多关于动态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 子句。父对象具有 Son 对象的集合,而 Son 对象又具有技能对象的集合。正如查询所示,我想知道每个父亲的名字以及他们拥有一定技能的儿子的数量。技能集将在运行时选择,因此即使在示例中,我们只有两组技能(2 where 子句),但在运行时可能是 10 个或任何数量的子句。
我认为我最大的问题是我似乎无法根据我的情况调整 StackOverflow 上给出的答案示例,因为我需要从顶级(父亲)获取信息以及从第三级(技能)获取与第二级(儿子)信息有关的信息。
如果需要,我将在明天发布我已经尝试过的示例代码。我现在做不到,因为我有点着急。任何帮助将不胜感激。
编辑:
我需要的是一种在运行时连接 where 子句的方法,具体取决于用户选择了多少过滤条件。不同的筛选条件是从外部源获取并在运行时构建的。所以例如:
在方案 1 中,可能有 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
};
场景 2:
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
};
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
};
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()
};
然后设计查询,以处理筛选器的 dyyanmic 性质。例如,我创造了父亲和儿子,儿子可以踢足球或排球。现在我的查询将只接受足球的 dyanmic 请求......这是我的做法:
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