Frage

Ich habe versucht, einen LINQ-Ausdruck in eine Methode umzugestalten, und bin auf beide gestoßen. "Internal .NET Framework Data Provider error 1025." und "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression." Ausnahme.

Hier sind die relevanten Teile des Entitätsmodells (mit EF 4.2 / LINQ to Entities):

public class Place : Entity
{
    public string OfficialName { get; protected internal set; }
    public virtual ICollection<PlaceName> { get; protected internal set; }
}

public class PlaceName : Entity
{
    public string Text { get; protected internal set; }
    public string AsciiEquivalent { get; protected internal set; }
    public virtual Language TranslationTo { get; protected internal set; }
}

public class Language : Entity
{
    public string TwoLetterIsoCode { get; protected internal set; }
}

Das grundlegende relationale Modell ist dies:

Place (1) <-----> (0..*) PlaceName (0..*) <-----> (0..1) Language

Ich versuche, eine Abfrage zu erstellen, die bei einer Suche angezeigt wird term, versuche zu finden Place unternehmen, deren OfficialName beginnt mit dem term ODER wer hat eine PlaceName deren Text oder AsciiEquivalent beginnt mit der Suche term. (Language habe ich keine Probleme, obwohl es Teil der Abfrage ist, weil PlaceNames sollte nur für die übereinstimmen CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName.)

Der folgende Code funktioniert:

internal static IQueryable<Place> WithName(this IQueryable<Place> queryable, 
    string term)
{
    var matchesName = OfficialNameMatches(term)
        .Or(NonOfficialNameMatches(term));
    return queryable.AsExpandable().Where(matchesName);
}

private static Expression<Func<Place, bool>> OfficialNameMatches(string term)
{
    return place => place.OfficialName.StartsWith(term);
}

private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
    var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
    return place => place.Names.Any(
        name =>
        name.TranslationToLanguage != null
        &&
        name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage
        &&
        (
            name.Text.StartsWith(term)
            ||
            (
                name.AsciiEquivalent != null
                &&
                name.AsciiEquivalent.StartsWith(term)
            )
        )
    );
}

Was ich als nächstes versuche, ist das umzugestalten NonOfficialNameMatches methode zum Extrahieren der name => ... ausdruck in eine separate Methode aus, damit er von anderen Abfragen wiederverwendet werden kann.Hier ist ein Beispiel, das ich ausprobiert habe: funktioniert nicht und wirft die Ausnahme "The parameter 'place' was not bound in the specified LINQ to Entities query expression.":

private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
    return place => place.Names.AsQueryable().AsExpandable()
        .Any(PlaceNameMatches(term));
}

public static Expression<Func<PlaceName, bool>> PlaceNameMatches(string term)
{
    var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
    return name =>
            name.TranslationToLanguage != null
            &&
            name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage
            &&
            (
                name.Text.StartsWith(term)
                ||
                (
                    name.AsciiEquivalent != null
                    &&
                    name.AsciiEquivalent.StartsWith(term)
                )
            );
}

Wenn ich das nicht habe .AsExpandable() kette ein NonOfficialNameMatches, dann bekomme ich die "Internal .NET Framework Data Provider error 1025." Ausnahme.

Ich bin gefolgt weitere Ratschläge hier wie mehrere Kombinationen von Aufrufen .Expand() auf die Prädikate, aber immer mit einer der oben genannten Ausnahmen enden.

Ist es überhaupt möglich, diesen Ausdruck mithilfe von LINQ to Entities mit LinqKit / PredicateBuilder in eine separate Methode auszuklammern? Wenn ja, wie?Was mache ich falsch?

War es hilfreich?

Lösung

Die folgende Methode sollte funktionieren:

private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
    Expression<Func<PlaceName, bool>> placeNameExpr = PlaceNameMatches(term);
    Expression<Func<Place, bool>> placeExpr =
        place => place.Names.Any(name => placeNameExpr.Invoke(name));
    return placeExpr.Expand();
}

BEARBEITEN:Zusätzliche Erklärungen hinzufügen

Der PlaceNameMatches methode funktioniert so, wie Sie es geschrieben haben.Ihre Probleme bestanden darin, wie Sie die Methode angewendet haben.Wenn Sie Teile eines Ausdrucks ausklammern möchten, befolgen Sie die 3 Schritte, die ich in der obigen Methode ausgeführt habe.

  1. Setzen Sie eine lokale Variable auf den Ausdruck, der von einer Methode erstellt wurde.

  2. Setzen Sie eine andere lokale Variable auf einen neuen Ausdruck, der den lokalen Variablenausdruck aufruft.

  3. Rufen Sie das LinkKit auf Expand Methode:dadurch werden alle aufgerufenen Ausdrücke erweitert

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