No puede refactorizar el uso de LINQ to entities y LinqKit / PredicateBuilder
Pregunta
He estado tratando de volver a factorizar una expresión LINQ en un método, y han estado funcionando en el "Internal .NET Framework Data Provider error 1025.
"y "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression.
"las excepciones.
Aquí están las partes pertinentes de la entidad (modelo de uso de 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; }
}
El basic modelo relacional es este:
Place (1) <-----> (0..*) PlaceName (0..*) <-----> (0..1) Language
Estoy tratando de crear una consulta que, cuando se da una búsqueda term
, trate de encontrar Place
las entidades cuyos OfficialName
se inicia con la term
O que tiene un PlaceName
cuya Text
o AsciiEquivalent
se inicia con la búsqueda term
. (Language
no es donde tengo problemas, aunque es parte de la consulta, porque PlaceName
s sólo deben coincidir para que la 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 ahora es refactorizar el NonOfficialNameMatches
método para extraer el name => ...
la expresión a cabo en un método independiente, de forma que pueden ser reutilizados por otras consultas.Aquí es un ejemplo que he probado, 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 el .AsExpandable()
de la cadena en NonOfficialNameMatches
, luego me sale la "Internal .NET Framework Data Provider error 1025.
"la excepción.
He seguido otros consejos aquí como varias combinaciones de invocar .Expand()
en los predicados, pero siempre terminan con una de las mencionadas excepciones.
Es incluso posible factor de esta expresión en un método independiente utilizando LINQ to entities con LinqKit / PredicateBuilder? Si es así, ¿cómo?¿Qué estoy haciendo mal?
Solución
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:La adición de más explicaciones
El PlaceNameMatches
el método que funciona como usted lo escribió.Sus problemas fueron en cómo usted utiliza el método.Si desea factor de partes de una expresión que seguir los 3 pasos que hice en el método anterior.
Establecer una variable local a la expresión creada por un método.
Definir otra variable local a una nueva expresión que Invoca el local de expresión variable.
Llame a la LinkKit
Expand
método:esto se expanda cualquier Invoca expresiones