我有谓词构建器,它具有谓词和内部谓词,并根据条件构建动态过滤器,假设我正在选择一个部门,在该部门下我将获取员工列表,一旦获得员工列表,我需要加载属于所选部门的每个员工的相应记录。
实现很久以前就已经完成了,如果部门没有太多员工,它可以正常工作,一旦超过 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;
发生这种情况可能是由于 .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 环境。
我添加了自己的表达式构建器引擎,即生成谓词的更好方法。 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;