Die Umgestaltung mit LINQ to Entities und LinqKit / PredicateBuilder ist nicht möglich

entity-framework-4 expression-trees linqkit linq-to-entities predicatebuilder

Frage

Ich habe versucht, einen LINQ-Ausdruck in eine Methode umzuwandeln, und habe sowohl den " Internal .NET Framework Data Provider error 1025. " als auch " The parameter 'xyz' was not bound in the specified LINQ to Entities query expression. "Ausnahmen.

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

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 das:

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

Ich versuche , eine Abfrage zu erstellen , die wird, wenn eine Suche gegebenen term , versuchen zu finden Place Personen , deren OfficialName beginnt mit dem term OR, der eine hat PlaceName , deren Text oder AsciiEquivalent beginnt mit der Suche term . ( Language ist nicht, wo ich Probleme habe, obwohl es Teil der Abfrage ist, da PlaceName s nur für den 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 versuchen möchte, ist die NonOfficialNameMatches Methode NonOfficialNameMatches , um den Ausdruck name => ... in eine separate Methode zu extrahieren, damit sie von anderen Abfragen wiederverwendet werden kann. Hier ist ein Beispiel, das ich versucht habe, das funktioniert nicht und löst die Ausnahme aus " 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 die .AsExpandable() Kette in NonOfficialNameMatches nicht habe, .AsExpandable() ich die Ausnahme " Internal .NET Framework Data Provider error 1025. NonOfficialNameMatches Internal .NET Framework Data Provider error 1025. ".

Ich habe hier andere Ratschläge wie zum Beispiel mehrere Kombinationen des Aufrufs von .Expand() auf die Prädikate .Expand() , aber immer mit einer der oben genannten Ausnahmen enden.

Ist es sogar möglich, diesen Ausdruck in eine separate Methode zu zerlegen, die LINQ to Entities mit LinqKit / PredicateBuilder verwendet? Wenn das so ist, wie? Was mache ich falsch?

Akzeptierte Antwort

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

EDIT: Hinzufügen zusätzlicher Erklärungen

Die Methode PlaceNameMatches funktioniert so, wie Sie sie geschrieben haben. Ihre Probleme bestanden darin, wie Sie die Methode verwendet haben. Wenn Sie Teile eines Ausdrucks ausklammern möchten, folgen Sie den 3 Schritten, die ich in der obigen Methode ausgeführt habe.

  1. Setzen Sie eine lokale Variable auf den von einer Methode erstellten Ausdruck.

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

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



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow