C# PredicateBuilder Entities: параметр «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.

Кто-нибудь еще сталкивался с этой ошибкой и знает, как ее решить?


person Neothor    schedule 01.06.2010    source источник


Ответы (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 возвращает Expression.

Как только мы преодолели ошибку, мы, безусловно, смогли создать сложные фильтры во время выполнения для структуры сущностей.

Редактировать:

Поскольку люди все еще комментируют и голосуют за это, я предполагаю, что это все еще полезно, поэтому я делюсь другим исправлением. По сути, я перестал использовать LinqKit и его построитель предикатов в пользу этого универсального предиката. Builder с тем же API, но без вызовов Expand, на который стоит обратить внимание.

person Mant101    schedule 02.06.2010
comment
Мне также пришлось удалить вызов AsExpandable() из исходного объекта IQueryable. - person Jeff Swensen; 21.05.2013
comment
Хороший ответ, но вводящий в заблуждение. Ответ BloodBaz - более простой и правильный ответ - person Mick; 25.11.2013

Я получил эту ошибку, и объяснение 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!
}

Надеюсь это поможет! :-)

person Chris Walsh    schedule 04.07.2012