문제

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

두 엔터티 모두 다른 엔터티의 컬렉션을 속성으로 갖고 있습니다(ID는 없음).이것이 내가 고군분투하고 있는 곳이다.다음과 같은 사용자 정의 표현이 있습니다. 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))
);

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

조금 혼란스러워요.

질문 자체에서 요구하는 내용은 다음과 같습니다.

contentQuery.Where(
    content => content.Tags.Any(tag => tag.Name == "blah")
);

실제로 질문자의 코드에 도달하기 위한 사고 과정이 무엇인지 잘 모르겠고, 그것이 실제로 무엇을 하는지도 완전히 확신할 수 없습니다.내가 정말로 확신하는 한 가지는 .AsQueryable() 호출이 완전히 불필요하다는 것입니다. .Tags가 이미 IQueryable이거나 .AsQueryable()이 대신 가짜로 사용할 것입니다. 그럴 필요는 없습니다.

오류는 'tags' 변수와 관련이 있습니다.LINQ to Entities는 값 컬렉션인 매개 변수를 지원하지 않습니다.더 빠른 답변에서 제안한 대로 단순히 tag.AsQueryable()을 호출하면 기본 메모리 내 LINQ 쿼리 공급자가 LINQ to Entities(또는 다른 관계형 공급자)와 호환되지 않기 때문에 작동하지 않습니다.

해결 방법으로 표현식 API를 사용하여 필터를 수동으로 구축할 수 있습니다(참조: 이 포럼 게시물) 다음과 같이 적용합니다.

var filter = BuildContainsExpression<Element, string>(e => e.Name, tags.Select(t => t.Name));
var query = source.Where(e => e.NestedValues.Any(filter));
tags.Select(testTag => testTag.Name)

태그 변수는 어디에서 초기화됩니까?그것은 무엇입니까?

메모:답변으로 회신하기보다는 질문 자체를 편집하십시오. 이것은 토론 스레드가 아니며 언제든지 스스로 재정렬할 수 있습니다.

태그 집합 중 하나로 표시된 모든 콘텐츠를 검색하는 경우:

IEnumerable<Tag> otherTags;
...
var query = from content in contentQuery
            where content.Tags.Intersection(otherTags).Any()
            select content;

LINQ To SQL을 사용하고 있는 것 같습니다. 이 경우 이 작업을 수행하기 위해 저장 프로시저를 작성하는 것이 더 나을 수 있습니다.이를 위해 LINQ를 사용하면 아마도 SQL Server에서는 실행되지 않을 것입니다. contentQuery 그리고 모든 것을 가져옵니다 .Tags 컬렉션.하지만 실제로 이를 확인하려면 서버를 설정해야 했습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top