2012-01-06 2 views
1

просмотрели многие сообщения здесь, на SO, и не нашли адреса для этого. Просто обратите внимание, что весь представленный здесь код упрощен, но представляет реальный код. У меня есть таблица данных, которая описывает некоторые свойства планов покрытия. Запрос, чтобы вернуть лучший матч выглядит примерно так:Коалесцирующие результаты в Linq

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 ?

Update: Я закончил с этой функцией в качестве замены:

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 к резервным подзапросам, и выясняется, что DefaultIfEmpty ненавидит его, если вы даете ему нуль, поэтому я использовал оператор коллаборации null для свертывания резервных уровней.

Я не знаю, почему они не дают вам DefaultIfEmpty, который принимает IEnumeration, это будет просто так:

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; 
} 

ответ

2

Я считаю, что .Select(x => x); фактически ничего не делает. Так что это можно удалить. Вы можете присоединяться к своим запросам, используя функцию объединения. Что касается проверки результатов поиска, вы можете исследовать эту функцию DefaultIfEmpty().

Я бы также рекомендовал resharper, помогая с предложениями по оптимизации LINQ.

Я также думаю, что вы должны соблюдать СУХИХ директоров и не имеют следующую строку кода:

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; 

} 
+0

Спасибо! Я не знал о DefaultIfEmpty, это именно то, что я искал, чтобы позаботиться об этой части. Я тоже ненавижу повторение, это довольно грязно. Я буду применять ваши предложения утром и отчитываться. –

Смежные вопросы