Domanda

Ho cercato di refatturare un'espressione LINQ in un metodo e sono rimasta in entrambe le eccezioni "Internal .NET Framework Data Provider error 1025." che "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression.".

Ecco le parti rilevanti del modello di entità (utilizzando EF 4.2 / LINQ in entità):

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

Il modello relazionale di base è questo:

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

Sto cercando di creare una query che, quando viene fornito una ricerca term, prova a trovare entità Place il cui OfficialName inizia con il term o chi ha un PlaceName il cui Text o AsciiEquivalent inizia con la ricerca term. (Language non è dove sto avendo problemi, anche se fa parte della query, perché i PlaceNames devono corrispondere solo per il CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName.)

Il seguente codice funziona :

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

Quello che sto cercando di fare il prossimo è il refattore del metodo NonOfficialNameMatches per estrarre l'espressione name => ... in un metodo separato, in modo che possa essere riutilizzato con altre query. Ecco un esempio che ho provato, quale non funziona e getta l'eccezione "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)
                )
            );
}
.

Quando non ho la catena .AsExpandable() in NonOfficialNameMatches, quindi ottengo l'eccezione "Internal .NET Framework Data Provider error 1025.".

Ho seguito Altri consigli qui come diverse combinazioni di richiamare .Expand() sui predicati, ma finiscono sempre con uno delle suddette eccezioni.

è persino possibile rivolgersi a questa espressione in un metodo separato utilizzando LINQ in entità con Linqkit / PredicationBuilder? Se è così, come? Cosa sto facendo male?

È stato utile?

Soluzione

Il metodo di seguito dovrebbe funzionare:

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

Modifica: aggiungere ulteriori spiegazioni

Il metodo PlaceNameMatches funziona come lo hai scritto.I tuoi problemi erano in come hai usato il metodo.Se si desidera effettuare il fattore di parti di un'espressione, seguire i 3 passaggi che ho fatto nel metodo sopra.

    .
  1. Impostare una variabile locale per l'espressione creata da un metodo.

  2. Imposta un'altra variabile locale in una nuova espressione che richiama l'espressione variabile locale.

  3. Chiama il metodo Expand LinkKit: questo espanderà qualsiasi espressione invocata

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top