2009-08-04 7 views
3

linq에서 엔티티의 하위 요소를 단일 linq 쿼리를 사용하여 필터링해야합니다. 이것이 가능한가?Linq에서 자식 컬렉션을 필터링하는 방법

두 개의 관련 테이블이 있다고 가정합니다. 구절과 절 번역. LINQ to SQL에 의해 생성 된 엔터티는 VerseTranslation 컬렉션 인 자식 개체를 포함하는 Verse 개체를 가지고 있습니다.

지금 나는 추적의 LINQ 쿼리

var res = from v in dc.Verses 
        where v.id = 1 
        select v; 

내가 ID 1이며, 각 구절의 목적은 모든 아이가 VerseTranslations에서 개체를 포함 구절의 컬렉션을 얻을 수있는 경우.

내가하고 싶은 기능은 Verse Translations의 하위 목록을 필터링하는 것입니다.

지금까지 익명으로 또는 다른 형식을 사용하여 유일한 방법은 생각해 냈습니다. 다음과 같이

var res= from v in dc.Verses 
        select new myType 
        { 
         VerseId = v.VerseId, 
         VText = v.Text, 
         VerseTranslations = (from trans in v.VerseTranslations 
               where languageId==trans.LanguageId 
               select trans 
        }; 

위의 코드는 작동하지만 새로운 클래스를 선언해야했습니다. 자식 테이블에 대한 필터링을 새 클래스를 선언 할 필요가 없도록 첫 번째 linq 쿼리에 통합 할 수있는 방식으로이를 수행 할 방법이 없습니까? 이 데이터베이스에서 오는 경우

감사합니다, MAC

답변

8

그래서 나는 Shiraz가 준 포인터 덕분에 마침내 작동하게 만들었습니다.

 DataLoadOptions options = new DataLoadOptions(); 
     options.AssociateWith<Verse>(item => item.VerseTranslation.Where(t => languageId.Contains(t.LanguageId))); 

     dc.LoadOptions = options; 

     var res = from s in dc.Verse 
        select s; 

이렇게하면 프로젝션이나 새로운 확장 클래스를 사용할 필요가 없습니다.

모든 사용자에게 감사드립니다.

0

, 당신은 첫 번째 문을 실행할 수 있습니다.

그런 다음 Where 절과 함께 VerseTranslations로드 또는 포함을 수행하십시오.

http://msdn.microsoft.com/en-us/library/bb896249.aspx

는 절과 VerseTranslations와 모델의 관계가 있습니까. 이 경우이 작업 할 수 있습니다

var res= from v in 
dc.Verses.Include("VerseTranslations").Where(o => languageId==o.LanguageId) 
select v; 
+0

링크에서 알 수 있듯이이 예제에서 btw는 단일 개체를 가져온 다음로드합니다. 내 경우에는 내가 res에서 컬렉션을 가지고 있고, 아직도 내 시나리오에 그것을 적응시킬 수 없었다. 어쩌면 그것의 잠의 부족 :/ – MAC

+0

ok..dumb 질문 ... 그러나 나는 포함 방법을 찾아 낼 수 없다 !! 예 데이터베이스에서오고 두 테이블에 관계가 있습니다. 그래서 dc는 datacontext이고 절은 테이블입니다. 하지만 나는 포함 기능을 얻을 수 없습니다. – MAC

+0

SQL에 엔티티 프레임 워크 또는 linq를 사용하고 있습니까? –

0

필터링 개체의 동봉 컬렉션,

var res = dc.Verses 
      .Update(v => v.VerseTranslations 
         = v.VerseTranslations 
          .Where(n => n.LanguageId == languageId)); 

확장 메서드 "업데이트"를 사용하여 HookedOnLinq

public static class UpdateExtensions { 

    public delegate void Func<TArg0>(TArg0 element); 

    /// <summary> 
    /// Executes an Update statement block on all elements in an IEnumerable<T> sequence. 
    /// </summary> 
    /// <typeparam name="TSource">The source element type.</typeparam> 
    /// <param name="source">The source sequence.</param> 
    /// <param name="update">The update statement to execute for each element.</param> 
    /// <returns>The numer of records affected.</returns> 
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update) { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (update == null) throw new ArgumentNullException("update"); 
     if (typeof(TSource).IsValueType) 
      throw new NotSupportedException("value type elements are not supported by update."); 

     int count = 0; 
     foreach(TSource element in source) { 
      update(element); 
      count++; 
     } 
     return count; 
    } 
} 
+0

에는 실제로이 기능이 내장되어 있지 않습니까? – MAC

0

에서 있습니까 그러한 방식으로 그것을 수행 할 방법이 없으므로, 자식 테이블 새로운 클래스를 선언 할 필요가 없도록 첫 번째 linq 쿼리에 통합 될 수 있습니까?

기술적으로 답은 no입니다. 하나의 엔티티 객체 (Verse, VerseTranslation)보다 많은 데이터를 반환하려는 경우 "프로젝트"할 일종의 객체가 필요합니다. 그러나, 당신은 명시 적으로 익명 형식을 사용하여 myType를 선언 주위를 얻을 수 있습니다 :

var res = from v in dc.Verses 
      select new 
      { 
       Verse = v, 
       Translations = (from trans in v.VerseTranslations 
           where languageId==trans.LanguageId 
           select trans).ToList() 
      }; 

var first = res.First(); 
Console.WriteLine("Verse {0} has {1} translation(s) in language {2}.", 
    first.Verse.VerseId, first.Translations.Count, languageId); 

컴파일러를 당신을 위해 적절히 형식의 절 및 번역 속성을 가진 클래스를 생성합니다. 이름으로 유형을 참조 할 필요가없는 경우 (예 : 명명 된 메소드에서 리턴 할 때)이 오브젝트를 거의 모든 용도로 사용할 수 있습니다.기술적으로 "선언"하지는 않지만, 당신은 여전히 ​​당신의 스펙에 따라 생성 될 새로운 타입을 사용하고 있습니다.

단일 LINQ 쿼리를 사용하는 한 모든 데이터를 구조화하는 방식에 따라 달라집니다. 제게는 원래 검색어가 가장 의미가있는 것처럼 보입니다 : 각 Verse을 필터링 된 번역 목록과 연결하십시오. 당신은 언어 당 하나의 번역을 기대하는 경우에, 당신은 당신의 하위 쿼리를 평평하게 SingleOrDefault (또는 FirstOrDefault)를 사용할 수도 있고, 그냥이 같은 SelectMany 사용 "구절 여러 번역이

var res= from v in dc.Verses 
     from t in v.VerseTranslations.DefaultIfEmpty() 
     where t == null || languageId == t.LanguageId 
     select new { Verse = v, Translation = t }; 

경우, 이것은 반환됩니다를 각 Verse/Translation 쌍에 대해 "행"을 선택하십시오. 나는 DefaultIfEmpty()을 왼쪽 조인으로 사용하여 번역이 누락 되어도 모든 절을 얻을 수 있도록합니다.

+1

답변에 "="이 있어야 위험한 "="표시가 나타납니다. – Timwi

+0

좋은 캐치 - 고정 – dahlbyk

관련 문제