2009-12-16 7 views
2

다음은 대략 수행하려는 작업의 대략적이고 간단한 코드 예제이며 예상대로 작동하지 않습니다. 나는 문제의 경우 Entity에 Linq를 사용하고 있습니다.Linq 루프에서 Where 절을 추가하는 데 도움이 필요합니다.

두 개의 날짜 절이있는 경우 기본적으로 DateClause의 끝에서 아무 것도 반환하지 않는 첫 번째 루프에서 하나의 날짜 절이 매우 효과적입니다. TextClause의 루프에서는 첫 번째 텍스트 절 이후에 모든 텍스트 절을 무시하는 것으로 보입니다.

내 절약 조항은 ANDed가 될 것이므로 텍스트 절을 작성한 다음 다른 절을 추가하면 추가해야하며 특히 Contains 메서드를 사용하면 더욱 집중된 결과를 얻을 수 있습니다.

날짜에 대한 기대치는이 날짜 범위를 수행 할 것으로 예상되지만, 두 날짜가있는 경우 범위에 올바른 날짜가있는 레코드가 있음에도 불구하고 항상 아무 것도 반환하지 않습니다.

나는 틀린 무엇인가 잘못하고있는 것을 확신한다. 그러나 나는 그것을 볼 수 없다.

enum Operators 
{ 
    Contains, 
    DoesNotContain, 
    GreaterThan, 
    LessThan 
} 

public void DoSomething(List<DateClauses> dateClauses, List<TextClauses> textClauses) 
{ 
    var query = from t in context.Table 
       where t.Enabled = true 
       select new 
       { 
        title = t.title 
        date = t.date 
       } 


    foreach (DateClause clause in dateClauses) 
    { 
     switch (clause.Operator) 
     { 
      case Operator.GreaterThan: 
       query = query.Where(l => l.date > clause.Date); 
       break; 
      case Operator.LessThan 
       query = query.Where(l => l.date < clause.Date); 
       break; 
     }  
    } 

    foreach (TextClause clause in textClauses) 
    { 
     switch (clause.Operator) 
     { 
      case Operator.Contains: 
       query = query.Where(l => l.title.Contains(clause.Text)); 
       break; 
      case Operator.DoesNotContain 
       query = query.Where(l => !l.title.Contains(clause.Text)); 
       break; 
     } 
    } 
} 

EDIT : 프로세스에서 enum 사용을 보여주기 위해 업데이트 된 예제 코드. 열거 형의 사용법을 보잘것없는 해결책으로 풀었을 때, Joel의 응답에 나와있는 코멘트에 예외가 생겼습니다.

나는 지금까지 내가 응답 한 것을 좋아하고 몇 가지 새로운 Linq 트릭을 배웠다. 나는 bool과 enum이 Linq와 많은 관련이 있다고 생각하지 않았기 때문에 예제를 사과했다. 변경 사항이 저에게 효과가있는 해결책을 찾는 데 도움이되기를 바랍니다. 지금까지 큰 반향을 보내 주셔서 다시 한번 감사드립니다.

+0

마찬가지로, 나는 이것이 효과가있을 것이라고 기대했을 것입니다. 추적을 설정하고 결과 쿼리가 어떻게 표시되는지 확인하는 것이 좋습니다. 물론 이것은 실제 코드가 아니기 때문에 다른 곳에서 잘못된 것이있을 수 있습니다. –

+0

.ToList()를 .Where()의 끝에 추가하십시오. – rmoore

+1

@rmoore : ** Noooooooooo! ** 추가 중.ToList()는 여기서 도움이되지 않으며 필요없는 위치에 추가하면 성능에 좋지 않습니다. –

답변

4

그냥 추측을하지만, 될 수있는 다음에 루프를 변경하면 다른 결과를 가지고?

foreach (DateClause clause in dateClauses) 
{ 
    var capturedClause = clause; 
    switch (clause.Operator) 
    { 
      case Operator.GreaterThan: 
        query = query.Where(l => l.date > capturedClause.Date); 
        break; 
      case Operator.LessThan 
        query = query.Where(l => l.date < capturedClause.Date); 
        break; 
    }    
} 

각 반복에 대한 루프 변수의 값이 아닌 루프 변수를 캡처하는 Where 조건을 만드는 중입니다. 결국 마지막 반복 후에 쿼리가 실행되므로 각 루프는 루프의 마지막 반복에 대한 값을 사용하여 동일하게됩니다. 임시 변수를 도입하면 각 반복마다 변수를 캡처 할 수 있습니다.

Eric Lippert의 blog about this subject도 참조하십시오.

+0

와우, 뭔가 간단해서 문제를 해결하여 루프를 사용할 수있었습니다. Ruben에게 감사드립니다. 그 foreach가 술어에 대해 어떻게 다른지, 정보 및 블로그 게시물에 대한 링크 덕분입니다. –

0

이전에는 아무런 문제없이이 작업을 수행했습니다. Wheres가 완료된 후 .Select를 끝까지 이동해야합니다. 또한 PredicateBuilder을 사용하여 동적 쿼리에 유연성을 추가했습니다. 이제는 추가 된 wheres에 대한 의미를 얻습니다. 여기서 적어도 "또는"의미를 원할 것입니다. PredicateBuilder를 사용하면 쉽게 할 수 있습니다 (무료입니다!).

+0

이것은 코드의 단순한 예입니다. 실제 코드에서 Where 절 메서드를 사용해야합니다. 동적 일 필요가 있기 때문에 사용자가 "필터링 된"내용과 변경되지 않은 내용을 제어합니다. 실행 시간. 선택은 그 위치에 있어야합니다. –

2
var query = context.Table 
     .Where(t => t.Enabled 
      && textClauses.Where(c => c.Contains).All(c => t.title.Contains(c.Text)) 
      && textClauses.Where(c => c.DoesNotContain).All(c => !t.title.Contains(c.Text)) 
      && dateClauses.Where(c => c.GreaterThan).All(c => t.date > c.Date)) 
      && dateClauses.Where(c => c.LesserThan).All(c => t.date < c.Date)) 
     ).Select(t => new { 
       title = t.title 
       date = t.date 
     }); 

여기에서 중요한 것은 현재 foreach 루프의 각 대신 .All()를 사용하는 리팩토링 할 수 있다는 것입니다. 또는 루프 내의 각 if 상태 일 수 있습니다. 당신이 정말로 여전히 곳의 각 탈옥 할 수 있습니다 원하는 경우

var query = context.Table.Where(t => t.Enabled).Select(t => new { 
       title = t.title 
       date = t.date 
     }); 

query = query.Where(t => textClauses.Where(c => c.Contains).All(c => t.title.Contains(c.Text)); 
query = query.Where(t => textClauses.Where(c => c.DoesNotContain).All(c => !t.title.Contains(c.Text)); 
query = query.Where(t => dateClauses.Where(c => c.GreaterThan).All(c => t.date > c.Date)); 
query = query.Where(t => dateClauses.Where(c => c.LesserThan).All(c => t.date < c.Date)); 
+0

데이트를 시도했지만 작동하지 않습니다. 컴파일하지만 런타임이 발생합니다. NotSupportedException "상수 값을 'Closure type'으로 만들 수 없습니다.이 컨텍스트에서는 원시 형식 (예 : Int32, String 및 Guid ') 만 지원됩니다." 이것은 Linq to Entity에서 지원하지 않는 것으로 보입니다. –

+0

이상한 이것은 확실히 지원됩니다. 여기에 나와있는 오류 메시지에서 눈에 띄는 핵심 단어는 '상수'입니다. 이 코드에서 생성 된 상수는 어디에도 없습니다. 이것은 상수를 초기화하기 위해 호출 할 함수에 있습니까? –

+0

상수는 내가 추측 한 실제 코드에있는 Enum입니다. 내 예제 절에서. 조항은 절이 될 것입니다 .Operator (열거 형)이며 If 문 대신 스위치가 있습니다. 나는 그것을 열거 형으로 만들었어야했다. 나는 그것이 중요 할 것이라고 생각하지 않았고, 예제를 단순하게 유지하고 싶었다. 나는 그것을 너무 단순하게 만들었을지도 모른다고 생각한다. 내가 한 것은 (c => c.Contains) (C => c.Operator == Operator.Contains)로 바꾸었지만 Linq가 생각한 것처럼 작동하지 않는다는 것을 배우는 것과 같은 결과를 얻었습니다 때때로. –

관련 문제