Arshad Khan
Arshad Khan

Reputation: 31

Stackoverflow Exception using PredicateBuilder with Entity Framework

I have Predicate builder, which is having predicate and inner predicate and building a dynamic filter based on conditions, let's say I am selecting one department, under that department I am getting list of employees, once I get the list of employees, I need to load the respective records for each and every employee who belongs to the selected department.

Implementation is already done long back and it works fine if department is having not too many employees, once it goes beyond 500 or 1000, the predicate builder is causing a stack overflow. Please see my code snippet for this - I am using .net framework 4.5.2.

Getting stackoverflow exception when assigning to inner predicate at this line with in loop, when record is beyond 1000 or 500, it loops based on the employee records.

Expression<Func<EmployeeTable, bool>> predicate =  PredicateBuilder.True<EmployeeTable>();
var innerPredicate = PredicateBuilder.False<EmployeeTable>();

case FilterBy.EmployeeName:
    if (!isEmpNameFilterExists)
    {
        foreach (string empName in item.FieldCollection)
        {
            innerPredicate = innerPredicate.Or(x => x.Name.Equals(empName, 
                                       StringComparison.OrdinalIgnoreCase));
        }
        predicate = predicate.And(innerPredicate.Expand());
    }
    break;

Upvotes: 3

Views: 810

Answers (2)

Arshad Khan
Arshad Khan

Reputation: 31

I have added my own Expression builder engine, i.e. much better way to generate the Predicate. PredicateBuilder works well with LINQ to Object, With EntityFramework its having the issue, because it generates the Lambda methods with full namespace of models and keep on adding with multiple search criteria. I felt like its having the limitations with large number of filters in Entity framework. In my case i was passing 728 count to just one field of Model, it was breaking with Stack-overflow exceptions. 728 lambdas method would be adding to the stack with full specific NAMESPACES.

Custom Expression is working totally fine in my case. Please find below Source code for the same.

var entityType = typeof(Emptable);
var parameter = Expression.Parameter(entityType, "a");
var containsMethod = typeof(string).GetMethod("Equals", new[] { typeof(string) });
//Switch Statement for EmployeeName Filter.
case FilterBy.EmployeeName:
    if (!isEmpNameFilterExists)
        {                            
        var propertyExpression = Expression.Property(parameter, "EmployeeName");
            foreach (string empName in item.FieldCollection)
            {
              var innerExpression = Expression.Call(propertyExpression, containsMethod, Expression.Constant(empName)); 
          body = Expression.OrElse(body, innerExpression);
             }
         }
break;

Upvotes: 0

Stephen Reindl
Stephen Reindl

Reputation: 5819

This might happen due to the (usually sufficient) but small stack for .NET applications (https://stackoverflow.com/a/823729/2298807). Evaluation on predicates is usually done as part of lamda functions and they use the stack. I do not now the predicate library in detail but I assume a use of recursive functions.

Anyhow: I would suggest to use Contains by building a List<string> containing the names:

Expression<Func<EmployeeTable, bool>> predicate =  
PredicateBuilder.True<EmployeeTable>();
var innerPredicate = PredicateBuilder.False<EmployeeTable>();

case FilterBy.EmployeeName:
    if (!isEmpNameFilterExists)
    {
        List<string> namesList = new List<string>();
        foreach (string empName in item.FieldCollection)
        {
            namesList.Add(empName);
        }
        predicate = predicate.And(x => namesList.Contains(x.Name));
     }
     break;

Note: Please check the syntax as I do not have a VS environment available at the moment.

Upvotes: 0

Related Questions