Linq All()/ Any()但不是空的

时间:2014-01-16 14:21:21

标签: linq entity-framework lambda linq-expressions

我有一个在几个地方使用的Linq表达式。我走了表达路线,因为没有逻辑方法来完成一些搜索逻辑而不会枚举一个非常大的表。

    private Expression<Func<Property, bool>> PropertyIsCompliant()
    {
        return (p) => p.CalculationSets.OfType<SingleDocumentCalculationSet>()
            .GroupBy(cs => cs.SourceDocument)
            .Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
            .SelectMany(cr => cr)
            .All(cr => cr.Outcome == CalculationOutcome.Success);
    }

我的模型是这样的:

  • 属性有许多CalculationSets
  • 每个CalculationSet也分配给Document
  • 每个CalculationSet都有一些CalculationResults
  • 每个CalculationResult都有一个结果

我正在尝试创建一个表达式,告诉我最近计算的所有结果是否按最近(即最近的不同结果)排序的文档分组是否成功。

我可以使用SelectMany子句从正确的CalculationSets返回所有CalculationResults。 我只是想知道如果集合不是空的,如果只返回true,它们都是Outcome.Success。

我理解All运算符会在空集合上自动返回true。我只是想不出办法来解决它!

4 个答案:

答案 0 :(得分:3)

所以真正的条件是没有不成功的结果。在这种情况下,使用Any并反转条件:

                //V-- notice the ! inverse operator here
    return (p) => !(p.CalculationSets.OfType<SingleDocumentCalculationSet>()
        .GroupBy(cs => cs.SourceDocument)
        .Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
        .SelectMany(cr => cr)
        .Any(cr => cr.Outcome != CalculationOutcome.Success));

答案 1 :(得分:1)

var countsBySuccess = 
 ...
 .GroupBy(cr => cr.Outcome == CalculationOutcome.Success) //group on success
 .Select(g => new { IsSuccessful = g.Key, Count = g.Count() });

您现在可以检查两个结果行,以确保不成功的计数为零,并且成功计数为非零。

关于性能,这需要在服务器端实现整个结果集并对其进行聚合。但它只这样做了一次。

如果您必须将计算结果用作更大查询的一部分,则必须使用另一个技巧:

!countsBySuccess.Any(g =>
    g.IsSuccessful && Count == 0 ||
    !g.IsSuccessful && Count != 0)

此布尔表达式通过一次扫描数据来确定您要查找的条件是否成立。

仅扫描一次数据非常重要。 只需写:

myItems.All(cr => cr.Outcome == CalculationOutcome.Success) && myItems.Any()

因为这会进行两次扫描。 SQL Server没有对此进行优化。

答案 2 :(得分:0)

我认为你正在回答你的问题 - 如果你知道All返回TRUE为空,那么你有两个检查要做。请原谅我的C#(我不确定var查询分配,希望你能得到这个想法),但你可以这样做:

private Expression<Func<Property, bool>> PropertyIsCompliant()
    {
        var query = (p) => p.CalculationSets.OfType<SingleDocumentCalculationSet>()
            .GroupBy(cs => cs.SourceDocument)
            .Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
            .SelectMany(cr => cr);

        return (query.Count > 0) & query.All(cr => cr.Outcome == CalculationOutcome.Success);
    }

答案 3 :(得分:0)

我没有意识到可以使用“&amp;&amp;”在表达式中。所以我设法结合了两个单独的表达式,给出了我需要的答案。 “&amp;&amp;”只有当两个表达式都评估为“true”时才返回true

            return (p) => 
            p.CalculationSets.OfType<SingleDocumentCalculationSet>()
            .GroupBy(cs => cs.SourceDocument)
            .Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
            .SelectMany(cr => cr).Any()
            &&
            p.CalculationSets.OfType<SingleDocumentCalculationSet>()
            .GroupBy(cs => cs.SourceDocument)
            .Select(g => g.OrderByDescending(d => d.DateTime).FirstOrDefault().CalculationResults)
            .SelectMany(cr => cr)
            .All(cr => cr.Outcome == CalculationOutcome.Success);