Question

J'ai essayé de refactoriser une expression LINQ en une méthode et j'ai rencontré à la fois le "Internal .NET Framework Data Provider error 1025." et "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression." des exceptions.

Voici les parties pertinentes du modèle d'entité (en utilisant 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; }
}

Le modèle relationnel de base est le suivant :

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

J'essaie de créer une requête qui, lors d'une recherche term, essayer de trouver Place entités dont OfficialName commence par le term OU qui a un PlaceName dont Text ou AsciiEquivalent commence par la recherche term. (Language ce n'est pas là que j'ai du mal, même si cela fait partie de la requête, car PlaceNames ne doit correspondre qu'au CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName.)

Le code suivant ça marche:

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

Ce que j'essaie de faire ensuite, c'est de refactoriser le NonOfficialNameMatches méthode pour extraire le name => ... expression dans une méthode distincte, afin qu’elle puisse être réutilisée par d’autres requêtes.Voici un exemple que j'ai essayé, qui ne marche pas et lève l'exception "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)
                )
            );
}

Quand je n'ai pas le .AsExpandable() chaîne dans NonOfficialNameMatches, alors j'obtiens le "Internal .NET Framework Data Provider error 1025." exception.

j'ai suivi d'autres conseils ici comme plusieurs combinaisons d'appels .Expand() sur les prédicats, mais aboutissent toujours à l'une des exceptions mentionnées ci-dessus.

Est-il même possible de factoriser cette expression dans une méthode distincte en utilisant LINQ to Entities avec LinqKit/PredicateBuilder ? Si c'est le cas, comment?Qu'est-ce que je fais mal?

Était-ce utile?

La solution

La méthode ci-dessous devrait fonctionner :

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

MODIFIER:Ajout d'explications supplémentaires

Le PlaceNameMatches la méthode fonctionne comme vous l’avez écrit.Vos problèmes résidaient dans la façon dont vous utilisiez la méthode.Si vous souhaitez prendre en compte certaines parties d'une expression, suivez les 3 étapes que j'ai suivies dans la méthode ci-dessus.

  1. Définissez une variable locale sur l'expression créée par une méthode.

  2. Définissez une autre variable locale sur une nouvelle expression qui appelle l'expression de variable locale.

  3. Appelez le LinkKit Expand méthode:cela développera toutes les expressions invoquées

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top