LINQ to Entities – Erstellen von Where-Klauseln zum Testen von Sammlungen innerhalb einer Viele-zu-Viele-Beziehung

StackOverflow https://stackoverflow.com/questions/110314

Frage

Ich verwende also das Linq-Entity-Framework.Ich habe 2 Entitäten: Content Und Tag.Sie stehen in einer Viele-zu-Viele-Beziehung zueinander. Content kann viele haben Tags Und Tag kann viele haben Contents.Ich versuche also, eine Abfrage zu schreiben, um alle Inhalte auszuwählen, bei denen alle Tag-Namen gleich sind blah

Die Entitäten haben beide eine Sammlung der anderen Entität als Eigenschaft (jedoch keine IDs).Hier kämpfe ich.Ich habe einen benutzerdefinierten Ausdruck für Contains (Wer auch immer mir helfen mag, Sie können davon ausgehen, dass ich ein „Enthält“ für eine Sammlung erstellen kann.)Ich habe diesen Ausdruck von: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2670710&SiteID=1

Bearbeiten 1

Am Ende habe ich meine eigene Antwort gefunden.

War es hilfreich?

Lösung

Nach der Lektüre über die PredicateBuilder , all die wunderbaren Beiträge zu lesen, die Menschen zu senden ich, auf anderen Websites zu veröffentlichen, und dann mehr auf Die Kombination von Prädikaten und rel="noreferrer"> oh .. und ich nahm ein wenig von Aufruf von Funktionen in LINQ up fragt (einige davon Klassen wurden von diesen Seiten) bereitgestellt.

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

Lassen Sie uns das gehackt Stück hinter sich bringen: (

Ich hatte Reflektor zu verwenden und die Expression Klasse zu kopieren, die als interne markiert. Ich hatte dann einige kleinere Änderungen, um es zu machen, um es zu bekommen zu arbeiten. Ich hatte zwei Ausnahmen zu erstellen (weil es newing interne Ausnahmen waren musste ich auch von der Readonlycollection () -Methode Rückkehr ändern.

return sequence.ToReadOnlyCollection<Expression>();

An:

return sequence.AsReadOnly();

Ich würde die Klasse schreiben, aber es ist ziemlich groß und ich will nicht diesen Beitrag Krempel mehr, als es wurde schon sein. Ich hoffe, dass in Zukunft kann diese Klasse aus meiner Bibliothek entfernt werden und dass Microsoft wird es öffentlich machen. Bewegen Sie sich auf ...

Ich habe eine ParameterRebinder Klasse:

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:

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

Und die letzte Klasse I hinzugefügt wurde 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; }

}

Das ist mein Ergebnis ... Ich konnte diesen Code ausführen und die daraus resultierenden „Inhalt“ Entitäten, die passende zurück „tag“ Entitäten aus den Tags, die ich gesucht habe!

    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, ob jemand Hilfe bei dieser gleichen Sache braucht, wenn Sie möchten, dass ich Sie Dateien für diese senden, oder einfach nur weitere Informationen benötigen.

Andere Tipps

Fasst it up ...

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

So ist das, was Sie erwarten?

Ich bin ein wenig verwirrt.

Dies ist, was die Frage selbst fragt:

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

Ich bin mir nicht sicher, was der Denkprozess des Fragestellers Code zu bekommen war, wirklich, und ich bin mir nicht ganz sicher, was genau es ist wirklich zu tun. Das einzige, was ich wirklich sicher bin, ist, dass .AsQueryable () -Aufruf völlig unnötig ist - entweder .Tags ist bereits ein IQueryable oder .AsQueryable () wird nur zu fälschen es für Sie - das Hinzufügen zusätzlicher Anrufe in denen es braucht daher nicht zu sein.

Der Fehler wird auf die ‚Tags‘ Variable bezogen. LINQ to Entities nicht akzeptiert einen Parameter, der eine Sammlung von Werten ist. Einfach tags.AsQueryable () aufgerufen wird - wie in einer ealier Antwort vorgeschlagen - wird nicht funktionieren, weil der Standard In-Memory-LINQ-Abfrage-Provider nicht kompatibel mit LINQ to Entities (oder anderen relationalen Providern)

.

Als Abhilfe können Sie manuell den Filter unter Verwendung des Ausdrucks API aufzubauen (siehe dieses Forum Post ) und wenden sie es wie folgt:

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)

Wo kommt die Tags Variable wird von initialisiert? Was ist das?

NOTIZ:Bitte bearbeiten Sie die Frage selbst, anstatt mit einer Antwort zu antworten – dies ist kein Diskussionsthread und sie können sich jederzeit neu sortieren

Wenn Sie nach allen Inhalten suchen, die mit einem Tag aus einer Reihe von Tags gekennzeichnet sind:

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

Es sieht so aus, als würden Sie LINQ To SQL verwenden. In diesem Fall ist es möglicherweise besser, wenn Sie eine gespeicherte Prozedur schreiben, um Folgendes auszuführen:Die Verwendung von LINQ zu diesem Zweck wird wahrscheinlich nicht auf SQL Server ausgeführt – es ist sehr wahrscheinlich, dass versucht wird, alles abzurufen contentQuery und alles holen .Tags Sammlungen.Allerdings müsste ich tatsächlich einen Server einrichten, um das zu überprüfen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top