LINQ两个Where子句

3

有人知道如何连接我的where子句吗?

我想通过第二个结果中找到的项来过滤主列表中的项。

我有以下示例代码:

@foreach (var artikel in Controller.Artikel
    .Where(x => x.LieferantenArtikel
                .Where(y => y.Lieferant.LieferantId == bestellung.LieferantId)
)
{
    <option value="@artikel.Artikelnummer">@artikel.Artikelnummer</option>
}

第一个 .Where 只是访问我的对象列表,其中包含我需要的实际检查。

3
Where()需要一个布尔值,可以在Where()内部使用Any()。 - Jochem Van Hespen
3
为什么你的用户界面有这样的过滤逻辑? - Peter Csala
1
@PeterCsala 因为它在 Blazor 服务器端应用程序中运行得非常好。 - Marvin Klein
3个回答

5
你把 .Where() 嵌套在另一个 .Where() 中使用是技术上正确的。但问题在于当前情况下,外层的 .Where() 没有被计算为布尔值,而这是必须的。 .Where() 的目的是定义集合的过滤器,以便得到该集合的子集。你可以通过检查是否存在任何项目满足该条件来验证: .Any()
@foreach (var artikel in Controller.Artikel
    .Where(x => x.LieferantenArtikel
                .Any(y => y.Lieferant.LieferantId == bestellung.LieferantId))
)
{
    <option value="@artikel.Artikelnummer">@artikel.Artikelnummer</option>
}

.


谢谢!这正是我所寻找的! - Marvin Klein

2
为了更好地理解如何有效使用LINQ,我希望能给其他答案增加一些背景信息:
你尝试使用的.Where()实际上是“存在”的意思。直接翻译成LINQ,应该是这样写的:
Controller.Artikel
    .Where(x =>
        x.LieferantenArtikel
            .Where(y => y.Lieferant.LieferantId == bestellung.LieferantId)
            .Count() > 0 // naive "exists", but bad; for reasons see below
    )
.Count() > 0的效率非常低,因为它需要执行.Count()来评估语句,而这又需要确定准确的结果集。
这就是.Any()发挥作用的地方:它仅通过检查它们并在第一个项目匹配时立即返回true来确定IEnumerable中是否至少有一个元素。因此,只有在没有匹配项时,才必须枚举和检查"LieferantenArtikel"的所有项目,否则较小的子集就足够了。

0

我发现非嵌套的LINQ更易读。使用SelectMany将其展开,然后再使用Where。请注意,您需要确保在Artikel中实现了Equals(),以便Distinct()能够正常工作。

var artikels = Controller.Artikel
    .SelectMany(x => x.LieferantenArtikel, (x, l) => (Artikel: x, Lieferant: l))
    .Where(x => x.Lieferant.LieferantId == bestellung.LieferantId)
    .Select(x => x.Artikel)
    .Distinct();

@foreach(var artikel in artikels)
{
    <option value="@artikel.Artikelnummer">@artikel.Artikelnummer</option>
}

虽然我在一般情况下也认同嵌套LINQ的观点,但我认为在这里可能不是一个好主意。你需要创建完整的扩展列表,为所有对创建一个对象,然后再次迭代所有对进行过滤,然后在结果中选择文章,然后再次创建集合,这反过来又会产生许多调用虚拟相等比较成员的需求,而且还需要你首先实现文章类型的相等比较。在我看来,为了避免一个嵌套级别而产生的所有开销并不值得。 - LWChris
@LWChris 虽然我理解你的观点,但我仍然不同意。我的性能优化方法很简单:你永远无法准确预测哪里会出现性能问题。因此,只有在问题出现时才去处理它。同时,编写简洁易读的代码也很重要。此外,对于这种情况实现 GetHashCodeEquals 通常也是一个好主意。 - Alexander Høst
但是.SelectMany(inflate, map).Where(filter).Select(project).Distinct([compare])真的比.Where(inflate.Any(filter))更简洁吗?如果你要问“存在哪里”,为什么不直接编码呢? - LWChris
1
@LWChris 这很公平。我同意这可能不够简洁。主要是我想要摆脱嵌套,所以我们在解决方案上并没有完全意见不合 - 在我看来两种方法都可以,只是我更倾向于非嵌套版本。 - Alexander Høst
1
是的,我同意,特别是如果嵌套部分不是一个方法而是另一个更大的LINQ链,或者如果嵌套层次超过1级。另外,一个不牺牲性能但可以降低感知复杂度的好方法是将外部lambda提取为一个带有良好名称的静态函数,例如topics.Where(HasNewAnswers)而不是topics.Where(t => t.Answers.Any(a => a.IsNew)),或使用扩展方法: categories.Where(c => c.HasQuestionsBy(user)) - LWChris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接