LINQ에서 어린이 컬렉션을 필터링하는 방법
-
22-07-2019 - |
문제
단일 LINQ 쿼리를 사용하여 LINQ에서 엔티티의 하위 요소를 필터링해야합니다. 이게 가능해?
두 개의 관련 테이블이 있다고 가정합니다. 구절과 versetranslations. LINQ에서 SQL에 의해 생성 된 엔티티는 Versetranslation 모음 인 Child Object를 포함하는 구절 객체를 갖는 것입니다.
이제 다음 linq 쿼리가 있다면
var res = from v in dc.Verses
where v.id = 1
select v;
나는 ID가 1 인 구절 모음을 얻고 각 구절 대상에는 세대의 모든 어린이 대상이 포함되어 있습니다.
제가하고 싶은 것은 자식 구절 목록을 필터링하는 것입니다.
지금까지 내가 생각해 낼 수있는 유일한 방법은 익명의 새로운 유형을 사용하는 것입니다. 다음과 같이
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
해결책
그래서 나는 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;
이것은 새로운 확장 클래스를 투영하거나 사용하지 않아도됩니다.
모든 의견을 보내 주셔서 감사합니다.
다른 팁
객체의 동봉 된 모음에서 필터링,
var res = dc.Verses
.Update(v => v.VerseTranslations
= v.VerseTranslations
.Where(n => n.LanguageId == languageId));
확장 방법 "업데이트"에서 후드 곤 린크
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;
}
}
이것이 데이터베이스에서 나오면 첫 번째 명령문을 실행할 수 있습니다.
그런 다음 WHERE 절을 가진 부하 또는 verseTranslation을 포함하십시오.
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;
자식 테이블의 필터링을 첫 번째 LINQ 쿼리에 통합하여 새 클래스를 선언 할 필요가 없도록 할 수있는 방법이 없습니까?
기술적으로 대답은 아니오입니다. 단일 엔티티 객체 (구절, 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 };
구절에 여러 번역이 있으면 각 구절/번역 쌍에 대해 "행"을 반환합니다. 나는 사용한다 DefaultIfEmpty()
왼쪽 가입으로서 번역이없는 경우에도 모든 구절을 얻을 수 있습니다.