LINQ-zu-Entitäten - Erstellen von Klauseln, um Sammlungen innerhalb einer Beziehung zwischen vielen und vielen zu testen

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

Frage

Also benutze ich das Linq-Entity-Framework. Ich habe 2 Entitäten: Content und Tag . Sie stehen in einer viel-zu-vielen Beziehung zueinander. Content kann viele Tags und Tag kann viele Contents . Ich versuche also, eine Abfrage zu schreiben, um alle Inhalte auszuwählen, bei denen Markierungsnamen gleich blah

Beide Entitäten haben eine Sammlung der anderen Entität als Eigenschaft (aber keine IDs). Hier kämpfe ich. Ich habe einen benutzerdefinierten Ausdruck für " Contains (Wer also mir helfen kann, kann davon ausgehen, dass ich für eine Sammlung ein "Enthalten" ausführen kann). Ich erhielt diesen Ausdruck von: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2670710&SiteID=1

Bearbeiten 1

Ich fand meine eigene Antwort.

Akzeptierte Antwort

Nach der Lektüre über die PredicateBuilder , all die wunderbaren Beiträge zu lesen , die Leute zu mir geschickt, auf anderen Websites zu veröffentlichen, und dann mehr zu lesen auf Prädikaten Kombination und Canonical Function Mapping .. ach ja , und nahm ich ein wenig von oben Aufruf von Funktionen in LINQ - Abfragen ( Einige dieser Klassen wurden von diesen Seiten übernommen.

Ich habe endlich eine Lösung !!! Obwohl es ein Stück gibt, das ein bisschen gehackt ist ...

Lassen Sie uns das gehackte Stück mit :(

Ich musste den Reflektor verwenden und die als intern markierte ExpressionVisitor-Klasse kopieren. Ich musste einige kleine Änderungen daran vornehmen, damit es funktioniert. Ich musste zwei Ausnahmen erstellen (da es sich dabei um interne Ausnahmen handelte). Außerdem musste ich die Rückgabe der ReadOnlyCollection () -Methode ändern:

return sequence.ToReadOnlyCollection<Expression>();

Zu:

return sequence.AsReadOnly();

Ich würde den Kurs posten, aber es ist ziemlich groß und ich möchte diesen Beitrag nicht mehr als sonst ärgern. Ich hoffe, dass diese Klasse in der Zukunft aus meiner Bibliothek entfernt werden kann und Microsoft sie öffentlich machen wird. Weitergehen ...

Ich habe eine ParameterRebinder-Klasse hinzugefügt:

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);
        }
    }

Dann habe ich eine ExpressionExtensions-Klasse hinzugefügt:

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);
        }
    }

Die letzte Klasse, die ich hinzugefügt habe, war 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; }

}

Dies ist mein Ergebnis ... Ich konnte diesen Code ausführen und die resultierenden "Inhalt" -Entitäten mit den entsprechenden "Tag" -Entitäten aus den von mir gesuchten Tags zurückholen!

    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();
    }

Bitte lassen Sie mich wissen, wenn jemand Hilfe mit derselben Sache benötigt, wenn Sie möchten, dass ich Ihnen Dateien dazu schicke oder einfach nur weitere Informationen.


Beliebte Antwort

Zusammenfassend ...

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

Also ist das, was Sie erwarten?

Ich bin ein wenig verwirrt.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum