Engr Umair
Engr Umair

Reputation: 130

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities

I have written a query that works fine when I use ToList() at the end of query before calling the predicate, but it throws an exception when I don't use ToList().

I don't want to use ToList() until the complete query is executed on the DB server otherwise, it will fetch thousands of records to memory, so I need to call the predicate once the complete query is executed.

Here is My Query without ToList() :

var myquery = (from p in se.CompanyRepresentatives
                             join qr in questionnaires on p.ID equals qr.RespondentID

                             join ra in se.Responses on qr.ID equals ra.QuestionnaireResponseID into raGroup
                             from res in raGroup.Where(r=> r.QuestionID == 1 || r.QuestionID == 2 || r.QuestionID == 3).DefaultIfEmpty(null)
                             
                             where
                            qr.QuestionnaireID == SurveyEntities.PROJECT_QUESTIONNAIRE_ID
                             select new ResultViewModel
                             {
                                 CompRep = p,
                                 QuestionnaireRes = qr,
                                 Res = raGroup.FirstOrDefault(x =>   x.QuestionID == 1),
                                 ProjectDeliverable = raGroup.FirstOrDefault(x =>   x.QuestionID == 2).Answer,
                                 ProjectDescription = raGroup.FirstOrDefault(x =>  x.QuestionID == 3).Answer,

                             });

    query= myquery.Where(ContainsAny(projectNamelist));

Here at the following line it throws the exception mentioned in title:

var nquery = query.ToList();

Here is my predicate builder :

static Expression<Func<ResultViewModel, bool>> ContainsAny(List<string> filters)
        {
            
            var predicate = PredicateBuilder.True<ResultViewModel>();
            foreach (var filter in filters)
            {
                string newfilter = filter.ToLower();
                predicate = predicate.And(cprep=> cprep.CompRep.CompanyName != null && cprep.CompRep.CompanyName.ToLower().Contains(newfilter)
                                            || ( cprep.CompRep.Email != null && cprep.CompRep.Email.ToLower().Contains(newfilter.ToLower()))
                                            || (  cprep.CompRep.FirstName != null && cprep.CompRep.FirstName.ToLower().Contains(newfilter.ToLower()))
                                            || (cprep.Res.Answer != null && cprep.Res.Answer.ToLower().Contains(newfilter.ToLower()))
                                            || (cprep.CompRep.CompanyDescription != null && cprep.CompRep.CompanyDescription.ToLower().Contains(newfilter.ToLower())));
            }
            return predicate;
        }

Here is PredicateBuilder:

public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }
        public static Expression<Func<T, bool>> False<T>() { return f => false; }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
        }
    }

Upvotes: 0

Views: 38

Answers (0)

Related Questions