2010-06-01 13 views
54

Necesitaba construir un filtro dinámico y quería seguir usando entidades. Por esta razón, quería usar PredicateBuilder de albahari.C# PredicateBuilder Entidades: El parámetro 'f' no estaba enlazado en la expresión de consulta LINQ to Entities especificada

creé el siguiente código:

var invoerDatums = PredicateBuilder.True<OnderzoeksVragen>(); 
var inner = PredicateBuilder.False<OnderzoeksVragen>(); 

foreach (var filter in set.RapportInvoerFilter.ToList()) 
{ 
    if(filter.IsDate) 
    { 
     var date = DateTime.Parse(filter.Waarde); 
     invoerDatums = invoerDatums.Or(o => o.Van >= date && o.Tot <= date); 
    } 
    else 
    { 
     string temp = filter.Waarde; 
     inner = inner.Or(o => o.OnderzoekType == temp); 
    } 
} 

invoerDatums = invoerDatums.And(inner); 
var onderzoeksVragen = entities.OnderzoeksVragen 
           .AsExpandable() 
           .Where(invoerDatums) 
           .ToList(); 

Cuando me encontré con el código que había sólo 1 de filtro que no era un filtro de fecha. Entonces solo el predicado interno se llenó. Cuando se ejecutó el predicado, recibí el siguiente error.

El parámetro 'f' no estaba obligado en el LINQ especificado a Entidades su búsqueda expresión.

Mientras buscaba una respuesta Encontré el siguiente page. Pero esto ya está implementado en el LINQKit.

¿Alguien más ha experimentado este error y sabe cómo solucionarlo?

Respuesta

121

me encontré con el mismo error, el problema parecía ser cuando tuve predicados hechos con PredicateBuilder que eran a su vez compuesto por otros predicados hechos con PredicateBuilder

por ejemplo, (A O B) Y (X o Y) donde un constructor crea A o B, uno crea X o Y y un tercero ANDs juntos.

Con solo un nivel de predicados, AsExpandable funcionó bien, cuando se introdujo más de un nivel recibí el mismo error.

No pude encontrar ninguna ayuda, pero a través de una prueba y error logré que todo funcionara. Cada vez que llamé a un predicado lo seguí con el método de extensión Expandir.

Aquí es un poco de código, cortado por simplicidad:

public static IQueryable<Submission> AddOptionFilter(
    this IQueryable<Submission> query, 
    IEnumerable<IGrouping<int, int>> options) 
{ 
    var predicate = options.Aggregate(
     PredicateBuilder.False<Submission>(), 
     (accumulator, optionIds) => accumulator.Or(ConstructOptionMatchPredicate(optionIds).Expand())); 
     query = query.Where(predicate.Expand());    
    return query; 
} 

consulta es IQueryable que ya ha tenido AsExpandable llama, ConstructOptionNotMatchPredicate devuelve una expresión.

Una vez que superamos el error, pudimos construir filtros complicados en tiempo de ejecución contra el marco de entidad.

Editar:

Dado que las personas todavía están comentando y votando esto supongo que sigue siendo útil por lo que estoy compartiendo otra solución. Básicamente, he dejado de usar LinqKit y su generador de predicados a favor de este Universal Predicate Builder que tiene la misma API pero no necesita Expandir llamadas, vale la pena echarle un vistazo.

+0

Tuve que quitar también la llamada a AsExpandable() de mi objeto IQueryable original. –

+2

Buena respuesta, pero engañosa. La respuesta de BloodBaz es la respuesta más simple y correcta – Mick

44

Tengo este error y la explicación de Mant101 me tiene la respuesta, pero que podría estar buscando un ejemplo más simple que causa el problema:

// This predicate is the 1st predicate builder 
var predicate = PredicateBuilder.True<Widget>(); 

// and I am adding more predicates to it (all no problem here) 
predicate = predicate.And(c => c.ColumnA == 1); 
predicate = predicate.And(c => c.ColumnB > 32); 
predicate = predicate.And(c => c.ColumnC == 73); 

// Now I want to add another "AND" predicate which actually comprises 
// of a whole list of sub-"OR" predicates 
if(keywords.Length > 0) 
{ 
    // NOTICE: Here I am starting off a brand new 2nd predicate builder.... 
    // (I'm not "AND"ing it to the existing one (yet)) 
    var subpredicate = PredicateBuilder.False<Widget>(); 

    foreach(string s in keywords) 
    { 
     string t = s; // s is part of enumerable so need to make a copy of it 
     subpredicate = subpredicate.Or(c => c.Name.Contains(t)); 
    } 

    // This is the "gotcha" bit... ANDing the independent 
    // sub-predicate to the 1st one.... 

    // If done like this, you will FAIL! 
// predicate = predicate.And(subpredicate); // FAIL at runtime! 

    // To correct it, you must do this... 
    predicate = predicate.And(subpredicate.Expand()); // OK at runtime! 
} 

Espero que esto ayude! :-)

Cuestiones relacionadas