No se puede refactorizar usando LINQ para Entidades y LinqKit / PredicateBuilder

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

Pregunta

He estado tratando de refactorizar una expresión LINQ en un método, y me he estado ejecutando tanto en el " Internal .NET Framework Data Provider error 1025. " y " The parameter 'xyz' was not bound in the specified LINQ to Entities query expression. "excepciones.

Aquí están las partes relevantes del modelo de entidad (usando EF 4.2 / LINQ para Entidades):

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

El modelo relacional básico es este:

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

Estoy intentando crear una consulta que, cuando se le presente un term búsqueda, intentará encontrar entidades de Place cuyo OfficialName comience con el term O que tenga un PlaceName cuyo Text o AsciiEquivalent comience con el term búsqueda. (El Language no es donde no estoy teniendo problemas, aunque es parte de la consulta, porque los PlaceName s solo deben coincidir con CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName ).

El siguiente código funciona :

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

Lo que estoy tratando de hacer a continuación es refactorizar el método NonOfficialNameMatches para extraer la expresión name => ... en un método separado, para que otras consultas puedan reutilizarlo. Aquí hay un ejemplo que probé, que no funciona y lanza la excepción " 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)
                )
            );
}

Cuando no tengo la cadena .AsExpandable() en NonOfficialNameMatches , obtengo la excepción " Internal .NET Framework Data Provider error 1025. ".

He seguido otros consejos aquí , como varias combinaciones de invocar .Expand() en los predicados, pero siempre terminan con una de las excepciones antes mencionadas.

¿Es incluso posible descomponer esta expresión en un método separado usando LINQ para Entidades con LinqKit / PredicateBuilder? ¿Si es así, cómo? ¿Qué estoy haciendo mal?

Respuesta aceptada

El siguiente método debería funcionar:

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

EDITAR: Agregar explicaciones adicionales

El método PlaceNameMatches funciona como lo escribiste. Sus problemas estaban en cómo usó el método. Si quieres factorizar partes de una expresión, sigue los 3 pasos que hice en el método anterior.

  1. Establecer una variable local a la expresión creada por un método.

  2. Establezca otra variable local en una nueva expresión que invoque la expresión de variable local.

  3. Llame al método LinkKit Expand : esto expandirá cualquier expresión invocada



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow