엔티티에 대한 LINQ - 다 대다 관계 내에서 컬렉션을 테스트 할 절 작성

c# entity-framework lambda linq many-to-many

문제

그래서, Linq 엔터티 프레임 워크를 사용하고 있습니다. ContentTag 가 2 개 있습니다. 그들은 서로에게 다 대다 관계에 있습니다. Content 많은 수 TagsTag 많은 수 있습니다 Contents . 그래서 나는 모든 태그의 이름이 blah 하는 모든 내용을 선택하는 쿼리를 작성하려고합니다.

엔티티는 둘 다 속성으로 다른 엔티티의 콜렉션을 갖지만 (ID는 없음). 이것은 내가 고심하고있는 곳이다. 나는 Contains 대한 커스텀 표현을 가지고있다. (그래서, 나를 돕는 사람이라면, 컬렉션을 위해 "contains"를 할 수 있다고 가정 할 수있다.) 이 표현식은 http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2670710&SiteID=1 에서 가져 왔습니다.

1 편집

나는 내 자신의 대답을 찾는 것을 끝내었다.

수락 된 답변

PredicateBuilder 에 대해 읽은 후 사람들이 저에게 보낸 훌륭한 게시물을 모두 읽고 다른 사이트에 게시 한 다음 술어표준 함수 매핑결합 하는 방법에 대해 자세히 읽은 다음 LINQ 쿼리에서 함수 호출 에서 약간의 정보를 얻었 습니다 ( 이 수업 중 일부는이 페이지에서 가져온 것입니다.)

나는 마침내 해결책을 가지고있다! !! 조금 해킹 된 조각이 있지만 ...

해킹 된 조각을 다음과 같이 만들어 봅시다.

리플렉터를 사용하고 내부로 표시된 ExpressionVisitor 클래스를 복사해야했습니다. 나는 그것을 작동시키기 위해 약간의 변화를 주어야했다. 두 가지 예외 (새 내부 예외가 있었기 때문에)를 작성해야했습니다. 또한 ReadOnlyCollection () 메서드의 반환을 다음과 같이 변경해야했습니다.

return sequence.ToReadOnlyCollection<Expression>();

에:

return sequence.AsReadOnly();

나는 클래스를 게시 할 것이다. 그러나 그것은 꽤 크다. 그리고 나는 그것이 벌써 가고있는 것보다 더 많이이 지위를 혼란시키고 싶지 않다. 미래에 클래스가 제 라이브러리에서 제거 될 수 있고 Microsoft가 공개 할 수 있기를 바랍니다. 계속 전진 ...

나는 ParameterRebinder 클래스를 추가했다 :

public class ParameterRebinder : ExpressionVisitor {
        private readonly Dictionary<ParameterExpression, ParameterExpression> map;

        public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) {
            this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
        }

        public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) {
            return new ParameterRebinder(map).Visit(exp);
        }

        internal override Expression VisitParameter(ParameterExpression p) {
            ParameterExpression replacement;
            if (map.TryGetValue(p, out replacement)) {
                p = replacement;
            }
            return base.VisitParameter(p);
        }
    }

그런 다음 ExpressionExtensions 클래스를 추가했습니다.

public static class ExpressionExtensions {
        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) {
            // build parameter map (from parameters of second to parameters of first)
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);

            // replace parameters in the second lambda expression with parameters from the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

            // apply composition of lambda expression bodies to parameters from the first expression 
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
            return first.Compose(second, Expression.And);
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
            return first.Compose(second, Expression.Or);
        }
    }

그리고 내가 추가 한 마지막 클래스는 PredicateBuilder입니다.

public static class PredicateBuilder {
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

}

이것은 내 결과입니다 ...이 코드를 실행하고 검색중인 태그의 "태그"엔티티와 일치하는 결과 "컨텐츠"엔티티를 다시 얻을 수있었습니다!

    public static IList<Content> GetAllContentByTags(IList<Tag> tags) {
        IQueryable<Content> contentQuery = ...

        Expression<Func<Content, bool>> predicate = PredicateBuilder.False<Content>();

        foreach (Tag individualTag in tags) {
            Tag tagParameter = individualTag;
            predicate = predicate.Or(p => p.Tags.Any(tag => tag.Name.Equals(tagParameter.Name)));
        }

        IQueryable<Content> resultExpressions = contentQuery.Where(predicate);

        return resultExpressions.ToList();
    }

이 파일을 보내거나 더 많은 정보가 필요하면 누구나이 같은 도움을 필요로하는지 알려주십시오.


인기 답변

요약 해 보면 ...

contentQuery.Where(
    content => content.Tags.Any(tag => tags.Any(t => t.Name == tag.Name))
);

그래서 당신이 기대하는 것이 무엇입니까?

나는 조금 혼란스러워.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.