将 PredicateBuilder 与实体框架结合使用时出现 Stackoverflow 异常

问题描述 投票:0回答:2

我有谓词构建器,它具有谓词和内部谓词,并根据条件构建动态过滤器,假设我正在选择一个部门,在该部门下我将获取员工列表,一旦获得员工列表,我需要加载属于所选部门的每个员工的相应记录。

实现很久以前就已经完成了,如果部门没有太多员工,它可以正常工作,一旦超过 500 或 1000 人,谓词构建器就会导致堆栈溢出。请参阅我的代码片段 - 我正在使用 .net Framework 4.5.2。

使用 in 循环分配给此行的内部谓词时出现 stackoverflow 异常,当记录超过 1000 或 500 时,它将根据员工记录进行循环。

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;
entity-framework predicatebuilder
2个回答
0
投票

发生这种情况可能是由于 .NET 应用程序的堆栈(通常足够)但很小(https://stackoverflow.com/a/823729/2298807)。对谓词的评估通常作为 lamda 函数的一部分完成,并且它们使用堆栈。我现在不详细介绍谓词库,但我假设使用递归函数。

无论如何:我建议通过构建包含以下名称的

Contains
来使用
List<string>

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;

注意:请检查语法,因为我目前没有可用的 VS 环境。


0
投票

我添加了自己的表达式构建器引擎,即生成谓词的更好方法。 PredicateBuilder 与 LINQ to Object 配合良好,而 EntityFramework 则存在问题,因为它生成具有完整模型命名空间的 Lambda 方法,并不断添加多个搜索条件。我觉得它在实体框架中存在大量过滤器的局限性。就我而言,我将 728 计数传递给模型的一个字段,它因堆栈溢出异常而中断。 728 lambdas 方法将添加到具有完整特定命名空间的堆栈中。

自定义表达式在我的例子中工作得很好。请在下面找到相同的源代码。

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;
© www.soinside.com 2019 - 2024. All rights reserved.