合并结果在Linq

时间:2012-01-06 01:12:05

标签: linq optimization linq-to-objects coalesce

已在SO上查看了很多帖子,但没有找到任何解决此问题的帖子。请注意,此处显示的所有代码均已简化,但代表了真实代码。我有一个数据表,描述了覆盖计划的一些属性。恢复最佳匹配的查询看起来像这样:

select coalesce
(
(select c.PercentOfCoverageA from CoveragePlans c
where c.coverage = :COVERAGE
and c.plancode = :PLANCODE
and c.statecode = :STATECODE),

(select c.PercentOfCoverageA from CoveragePlans c
where c.coverage = :COVERAGE
and c.plancode = :DEFAULTPLANCODE
and c.statecode = :STATECODE),

(select c.PercentOfCoverageA from CoveragePlans c
where c.coverage = :COVERAGE
and c.plancode = :DEFAULTPLANCODE
and c.statecode = :COUNTRYWIDE)
) as PercentOfCoverageA
from dual

这是一个很小的表(几十行)受到很多打击并且不经常更改,因此我想将其带入内存并使用Linq选择数据以加快速度。

我有这个功能,它完全按照我想要的方式返回第一个匹配:

decimal GetCoveragePercentage(string coverage, string planCode, string stateCode)
{
    IEnumerable<CoveragePlan> result = Coverages
        .Where(x => x.Coverage == coverage && x.PlanCode == planCode && x.StateCode == stateCode)
        .Select(x => x);

    if (!result.Any())
    {
        result = Coverages
            .Where(x => x.Coverage == coverage && x.PlanCode == defaultPlanCode && x.StateCode == stateCode)
            .Select(x => x);
    }

    if (!result.Any())
    {
        result = Coverages
            .Where(x => x.Coverage == coverage && x.PlanCode == defaultPlanCode && x.StateCode == countryWide)
            .Select(x => x);
    }

    return result.First().PercentOfCoverageA;
}

我的问题是:执行此Linq查询是否有更好的方法(更快,更少的代码,更少的重复)?

更新:我最终将此功能作为替代品:

decimal GetCoveragePercentage(string coverage, string planCode, string stateCode)
{
    return Coverages.Where(x => x.Equals(coverage, planCode, stateCode))
        .DefaultIfEmpty(Coverages.Where(x => x.Equals(coverage, defaultPlanCode, stateCode)).FirstOrDefault()
            ?? Coverages.Where(x => x.Equals(coverage, defaultPlanCode, defaultStateCode)).First())
        .First().PercentOfCoverageA;
}

DefaultIfEmpty需要实例而不是IEnumeration实例。这导致我在后备子查询中添加了First / FirstOrDefault,并且事实证明,如果你给它一个null,DefaultIfEmpty讨厌它,所以我使用null合并操作符来汇总后备级别。

我不确定他们为什么不给你一个接受IEnumeration的DefaultIfEmpty,它就是这样:

public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> defaultValue)
{
    return (source != null && source.Any()) ? source : defaultValue;
}

实际上,我认为我将使用该扩展方法,并将我的功能设为:

decimal GetCoveragePercentage(string coverage, string planCode, string stateCode)
{
    return Coverages.Where(x => x.Equals(coverage, planCode, stateCode))
        .DefaultIfEmpty(Coverages.Where(x => x.Equals(coverage, defaultPlanCode, stateCode)))
        .DefaultIfEmpty(Coverages.Where(x => x.Equals(coverage, defaultPlanCode, defaultStateCode)))
        .First().PercentOfCoverageA;
}

1 个答案:

答案 0 :(得分:2)

我相信.Select(x => x);实际上什么也没做。这样就可以删除了。您可以使用union函数加入查询。至于如果没有结果检查,您可以使用此函数DefaultIfEmpty()进行调查。

我还建议resharper对优化LINQ的建议有所帮助。

我还认为你应该遵守DRY原则并且没有这行代码:

x.Coverage == coverage && x.PlanCode == defaultPlanCode && x.StateCode == stateCode

取而代之的是:

x.Equals(coverage,defaultPlanCode,stateCode)

我建议您的方法的linq看起来像这样(确保添加等于方法优化以及此):

decimal GetCoveragePercentage(string coverage, string planCode, string stateCode)
{
    return Coverages
        .Where(x => x.Coverage == coverage && x.PlanCode == planCode && x.StateCode == stateCode)
        .DefaultIfEmpty(Coverages.Where(x => x.Coverage == coverage && x.PlanCode == defaultPlanCode && x.StateCode == stateCode))
        .DefaultIfEmpty(Coverages.Where(x => x.Coverage == coverage && x.PlanCode == defaultPlanCode && x.StateCode == countryWide))First().PercentOfCoverageA;

}