LINQ to entities - 構建where子句以在多對多關係中測試集合

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

所以,我正在使用Linq實體框架。我有2個實體: ContentTag 。他們彼此處於多對多的關係中。 Content可以有很多TagsTag可以有很多Contents 。所以我正在嘗試編寫一個查詢來選擇任何標籤名稱等於blah所有內容

實體都將另一個實體的集合作為屬性(但沒有ID)。這是我在努力的地方。我確實有Contains的自定義表達式(所以,無論誰可以幫助我,你可以假設我可以為一個集合做一個“包含”)。我得到了這個表達式: http//forums.microsoft.com/MSDN/ShowPost.aspx?PostID = 2670710&SiteID = 1

編輯1

我最終找到了自己的答案。

一般承認的答案

閱讀了有關PredicateBuilder的內容 ,閱讀了人們發給我的所有精彩帖子,在其他網站上發布,然後閱讀更多關於Combining PredicatesCanonical Function Mapping的內容 ..哦,我從LINQ查詢中的Calling函數中找到了一些內容(其中一些類是從這些頁面中獲取的)。

我終於有了解決方案!雖然有一件有點被黑了......

讓我們得到被黑的片斷:(

我不得不使用反射器並複制標記為內部的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))
);

那是你所期待的那樣嗎?

我有點困惑。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因