C # PredicateBuilder Entities: параметр 'f' не был связан в указанном выражении запроса LINQ to Entities - PullRequest
54 голосов
/ 01 июня 2010

Мне нужно было создать динамический фильтр, и я хотел продолжать использовать сущности. По этой причине я хотел использовать 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 ]

122 голосов
/ 02 июня 2010

Я столкнулся с той же ошибкой, проблема возникла, когда у меня были предикаты, созданные с помощью PredicateBuilder, которые в свою очередь были составлены из других предикатов, созданных с помощью PredicateBuilder

например. (A ИЛИ B) И (X ИЛИ Y), когда один строитель создает A ИЛИ B, один создает X ИЛИ Y, а третий AND соединяет их вместе.

С одним уровнем предикатов 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;
}

Запрос - это IQueryable, для которого уже был вызван AsExpandable, ConstructOptionNotMatchPredicate возвращает выражение.

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

Edit:

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

44 голосов
/ 05 июля 2012

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

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

...