Объекты C# PredicateBuilder: параметр 'f' не был связан в указанном выражении запроса LINQ to Entities
Мне нужно было создать динамический фильтр, и я хотел продолжать использовать сущности. По этой причине я хотел использовать PredicateBuilder от albahari.
Я создал следующий код:
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();
Когда я запускал код, был только 1 фильтр, который не был фильтром даты. Таким образом, был заполнен только внутренний предикат. Когда предикат был выполнен, я получил следующую ошибку.
Параметр 'f' не был связан в указанном выражении запроса LINQ to Entities.
В поисках ответа я нашел следующую страницу. Но это уже реализовано в LINQKit.
Кто-нибудь еще сталкивался с этой ошибкой и знает, как ее решить?
2 ответа
Я столкнулся с той же ошибкой, проблема, казалось, была, когда у меня были предикаты, сделанные с PredicateBuilder, которые в свою очередь были составлены из других предикатов, сделанных с PredicateBuilder
Например, (A ИЛИ B) И (X ИЛИ Y), где один строитель создает A ИЛИ B, один создает X ИЛИ Y, а третий И объединяет их.
Только с одним уровнем предикатов AsExpandable работал нормально, когда было введено более одного уровня, я получил ту же ошибку.
Я не смог найти какую-либо помощь, но путем проб и ошибок я смог заставить вещи работать. Каждый раз, когда я вызывал предикат, я следовал за ним методом расширения Expand.
Вот фрагмент кода, упрощенный для упрощения:
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;
}
Query - это IQueryable, для которого уже был вызван AsExpandable, ConstructOptionNotMatchPredicate возвращает выражение.
После того, как мы справились с ошибкой, мы, безусловно, смогли создать сложные фильтры во время выполнения на основе сущности.
Редактировать:
Поскольку люди все еще комментируют и голосуют, я полагаю, что это все еще полезно, поэтому я делюсь другим решением. По сути, я перестал использовать LinqKit и его построитель предикатов в пользу этого универсального построителя предикатов, который имеет тот же API, но не нуждается в вызовах Expand, которые стоит проверить.
Я получил эту ошибку, и объяснение Mant101 дало мне ответ, но вы, возможно, ищете более простой пример, который вызывает проблему:
// 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!
}
Надеюсь это поможет!:-)