2014-01-16 5 views
2

몇 군데에서 사용되는 Linq 표현식이 있습니다. 그렇지 않으면 매우 큰 테이블을 열거하지 않고 검색 논리를 달성하는 논리적 인 방법이 없었기 때문에 표현 경로를 따라갔습니다. Linq All()/Any() 비어 있지 않음

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

내 모델

같은 있습니다 :

  • 속성이
  • 각 CalculationSet 또한 문서에 할당 많은 CalculationSets있다
  • 각 CalculationSet은 CalculationResults을 가지고 있습니다
  • 각 CalculationResult 결과가있다

가장 최근의 (즉 가장 최근의 별개의 결과) 문서로 그룹화 된 가장 최근의 계산 세트의 모든 결과가 성공했는지 알려주는 표현식을 작성하려고합니다.

SelectMany 절은 올바른 CalculationSets에서 모든 CalculationResults를 반환 할 수 있습니다. 컬렉션이 비어 있지 않고 모두 Outcome.Success 인 경우에만 true를 반환하는 방법을 알 수 없습니다.

나는 All 연산자가 빈 콜렉션에 대해 true를 자동으로 반환한다는 것을 알고 있습니다. 나는 그 길을 생각할 수 없다!

답변

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); 
    } 
+1

"true"로 평가하는 경우에만 true를 돌려줍니다. – usr

+0

저는 SQL로 올바르게 변환되는 비슷한 솔루션을 사용했습니다 (아래). –

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

당신은 지금 확인하기 위해 두 개의 결과 행을 검사 할 수 있습니다 실패 카운트가 0이고 성공적인 카운트가 0이 아님을 나타냅니다.

성능과 관련하여 서버 측 전체 결과 집합을 구체화하고 집계해야합니다. 그러나 그것은 오직 한 번뿐입니다.

당신이 더 큰 쿼리의 일부로 계산 결과를 사용해야하는 경우, 당신은 또 다른 트릭을 사용해야합니다

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

이 부울 표현식은 당신이 찾고있는 조건이 하나의 데이터 스캔을 함께 보유 여부를 확인합니다.

데이터를 한 번만 스캔하는 것이 중요합니다. 단순히 기록하지를 수행

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

을하는 두 개의 스캔을 수행하기 때문에. SQL Server는이를 최적화하지 않습니다.

+0

제가 걱정했던 성능 문제는 SQL DB에서 응용 프로그램으로 모든 레코드를 가져 오는 것입니다. 필자는 SQL DB에 대해 2 가지 별도의 검사를 덜 우려하고 있습니다. 나는 당신의 "제안하지 마라"제안과 비슷한 해결책을 가지고 갔다! –

+0

두 가지 스캔 작업을 마쳤다면 좋은 해결책입니다. – usr

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)); 
+0

오류가 있으면 false를 반환해야하지만 true를 반환합니다. – usr

0

나는 표현에 "& &"을 사용하는 것이 가능했다 몰랐어요.그래서 저는 제가 필요로하는 답을주는 두 개의 서로 다른 표현을 결합 할 수있었습니다. 은 "& &"두 표현식이 모두이 번역 SQL되지 않았거나, 당신이 그것을 강제하는 경우가 비효율적 일 것입니다

  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); 
+1

와우, 그게 많은 중복이야. 나는 내 자신의 의견을 말할지라도 내 솔루션을 선호한다. – usr

+0

첫 번째 쿼리는 CalculationSet이 있는지 확인해야하기 때문에 변경되었다. 따라서 그룹화, 정렬, 첫 번째 쿼리를 선택하지 않아도됩니다. –

관련 문제