【问题标题】:LINQ two Where clausesLINQ 两个 Where 子句
【发布时间】:2020-10-12 12:57:47
【问题描述】:

有人知道我如何链接 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 只是访问我的对象列表,它有我需要的真正检查。

【问题讨论】:

  • Where() 需要一个布尔值,在 Where() 中使用 Any()
  • @MarvinKlein 为什么你的 UI 中有这样的过滤逻辑?
  • @PeterCsala 因为它在 blazor 服务器端应用程序中的工作方式类似于魅力。

标签: c# linq


【解决方案1】:

您将.Where() 链接到.Where() 的方式在技术上是正确的。问题是当前情况下的外部.Where() 不会评估为布尔值。然而,这是一个要求。 .Where() 的目的是为生成该集合的子集的集合定义过滤器。您可以检查.Any() item 是否满足该条件:

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

.

【讨论】:

  • 谢谢!这正是我搜索过的!
【解决方案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() &gt; 0 但是效率很低,因为这需要执行.Count() 来评估语句,而这又需要确定准确的结果集。

这就是.Any() 介入的地方:它仅通过检查它们来确定IEnumerable 中是否至少有一个元素,并在第一项匹配时立即返回true。所以只有在没有匹配的情况下,“LieferantenArtikel”的所有项目都必须被枚举和检查,否则一个较小的子集就可以了。

【讨论】:

    【解决方案3】:

    我发现非嵌套的 LINQ 更具可读性。用SelectMany 把事情弄平,然后用Where。请注意,您需要确保 Equals()Artikel 中实现,以便 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 虽然我同意你的观点,但我仍然不同意。我的性能方法很简单:您永远无法正确预测性能问题的所在。在它出现时处理它。同时,编写简洁易读的代码。此外,在这样的事情上实现GetHashcodeEquals 通常是个好主意。
    • 但是.SelectMany(inflate, map).Where(filter).Select(project).Distinct([compare]) 真的比.Where(inflate.Any(filter)) 更简洁吗?如果您要问“在哪里存在”,为什么不编码呢?
    • @LWChris 这很公平。我同意它可能不那么简洁。这是我主要想摆脱的嵌套,所以我们在这里的解决方案并不完全不同 - 在我看来两者都很好,我只是倾向于更喜欢非嵌套版本。
    • 是的,我同意,特别是如果嵌套部分不是一种方法而是另一个更大的 LINQ 链,或者嵌套深度超过 1 级。顺便说一句,在不牺牲性能的情况下降低感知复杂性的另一种好方法是将外部 lambda 提取到一个具有好听名称的静态函数中,例如 topics.Where(HasNewAnswers) 而不是 topics.Where(t =&gt; t.Answers.Any(a =&gt; a.IsNew)),或者使用扩展名:categories.Where(c =&gt; c.HasQuestionsBy(user))
    猜你喜欢
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    相关资源
    最近更新 更多