0

Generic Repository 패턴을 사용하여 EF 4.1 DbContext를 추상화합니다. 나는 또한 쿼리와 저장소 (들)에 변경 사항을 커밋하기 위해 서비스 계층을 사용하고 있습니다. 어쨌든, 여기서 내가 성취하고자하는 것은 사용자가 검색 창에 검색 문구를 입력 할 수있게하는 것입니다. 그런 다음 SearchService는 TopLevel 카테고리, 하위 카테고리 또는 이름에 검색 구문을 포함하는 항목을 찾기 위해 데이터베이스를 쿼리해야합니다. 첫눈에, 나는 그것이 간단한 일일 것이라고 생각했지만, 분명히 일들은 조금 더 복잡합니다.GenericRepository Pattern과 SearchService를 사용하여 검색 기능

public IList<Item> Search(string searchPhrase) 
    { 
     var result = new List<Item>(); 

     var tmp = from c in _repository.GetQuery<TopLevelCategory>(c=>c.Children) 
        where c.Name.Contains(searchPhrase) 
        select c; 
     if(tmp.Count() > 0) 
     { 
      foreach (var c in tmp) 
      { 
       var children = c.Children; 
       foreach (var childCategory in children) 
       { 
        result.Concat(childCategory.Items); 
       } 
      } 
     } 

     var tmp2 = from c in _repository.GetQuery<ChildCategory>(c=>c.Items) 
       where c.Name.Contains(searchPhrase) 
       select c; 
     if(tmp.Count() > 0) 
     { 
      foreach (var childCategory in tmp2) 
      { 
       result.Concat(childCategory.Items); 
      } 
     } 

     var tmp3 = from c in _repository.GetQuery<Item>() 
        where c.Title.Contains(searchPhrase) 
        select c; 
     if(tmp3.Count() > 0) 
     { 
      result.Concat(tmp3); 
     } 
     return result; 
    } 
} 

내가 그 추한 모습을 알고 엉망,하지만 난 그냥 그것을 올바른 결과를 반환하는 경우 볼 수있는 기회를 제공했다 : 여기에 내가 할 노력거야.

예외 정보 : System.InvalidOperationException : 글쎄 그것은하지 않았다, 그것은 다음과 같은 예외를 던졌다 가 먼저 닫아야이 명령과 관련된 열린 DataReader가 가 이미 있습니다.

Source: 

Line 31:   foreach (var childCategory in children) 
Line 32:   { 
Line 33:     result.Concat(childCategory.Items); 
Line 34:   } 

어쨌든 ...이 일을 더 똑똑한 방법이 어떤 제안이있다?

답변

2

예외는 DataReader를 열려서 자녀와 함께 최상위 범주를로드했지만 내부 foreach 루프에서 지연로드를 트리거하고 있다고합니다. 즉 게으른로드 항목을 열고 읽을 다른 DataReader가를 reaquires :

// Iterate top level categories => fist openned DataReader 
foreach (var c in tmp) 
{ 
    // Child category is eager loaded 
    var children = c.Children; 
    foreach (var childCategory in children) 
    { 
     // Items are not eager loaded => trigger lazy loading and open new DataReader 
     result.Concat(childCategory.Items); 
    } 
} 

당신이 당신의 연결 문자열을 수정하고 MARS 지원 MultipleActiveResultSets=true을 추가해야이 문제를 해결하기 위해. MARS는 적어도 SQL Server 2005 및 2008에서 지원됩니다.이 문제를 피하는 또 다른 방법은 열심히로드하는 항목입니다.

데이터베이스 수준에서 전체 텍스트 검색을 수행하는 것처럼 보입니다.

+0

@ 라디 슬라브 Mrnka : 답변 해 주셔서 감사합니다. 총체적인 의미를가집니다. 예, 맞습니다. 하위 레벨 카테고리를 최상위 카테고리와 함께 포함하고 있지만 항목을 포함 할 수 있는지 여부는 알 수 없습니다. 최상위 범주 클래스의 항목에 대한 탐색 속성이 없기 때문입니다. 이 문제를 해결할 방법이 있습니까? MARS는 어떨까요? 성능에 영향을 미칩니 까? – Kassem

+0

EF에 연결 문자열을 만들도록 허용하면 MARS가 기본 모드입니다 (예 : EDMX를 사용할 때). 시나리오에서 MARS를 피할 방법이 없습니다. 이 경우 성능에 문제가 없어야합니다. MARS와 관련된 성능에 대한 설명은 다음을 참조하십시오. http://msdn.microsoft.com/en-us/library/ms345109%28v=sql.90%29.aspx#marsins_topic9 –

+0

@Ladislav Mrnka : 연결 문자열에 MARS를 추가했습니다. 그것을 디버깅했다.분명히 Item 엔티티를 포함하고 있지 않기 때문에 최상위 범주 쿼리로 항목을 검색하지 않으므로 해결 방법이 필요합니다 ... 그리고 그런데 어떤 이유로 쿼리가 끝이없는 내부로 들어갑니다 루프 StackOverflowException 일으키는. 이견있는 사람? – Kassem

0

오류는 MARS 때문일 수 있습니다. MARS (Multiple Active Result Sets)를 활성화하기 만하면 연결 문자열에 'MultipleActiveResultSets = True'를 추가하면됩니다. 당신은 TopLevel이, Childlevel 및 항목의 이름을 조인 뷰를 만들 수 있습니다 here


  1. 을 확인합니다. 그런 다음이 뷰를 엔터티로 노출합니다. EF는 디자이너가 ID 필드를 결정하려고 할 때보기에 문제가 있음을 기억하십시오.
  2. 더 나은/강력한 쿼리 기능이 필요한 경우에 대비하여 lucene을 볼 수 있습니다.