使用谓词构建器的LinqKit堆栈溢出异常

时间:2010-06-08 10:07:01

标签: linq-to-sql

我正在使用LINQ和LINQKit在C#中编写应用程序。我有一个非常大的数据库表,里面有公司注册号。

我想做一个LINQ查询,它将产生等效的SQL: select * from table1 where regno in('123','456') 'in'子句可能有数千个术语。

首先,我从Country等领域获得公司注册号。

然后我将所有公司注册号添加到谓词中:

        var predicate = PredicateExtensions.False<table2>();
        if (RegNos != null)
        {
            foreach (int searchTerm in RegNos)
            {
                int temp = searchTerm;
                predicate = predicate.Or(ec => ec.regno.Equals(temp));
            }
        }

在Windows Vista Professional上添加4063个术语后发生堆栈溢出异常。在Windows Server 2003上,在添加约1000个术语后发生堆栈溢出异常。我必须快速解决这个问题才能进行演示。

为了解决这个问题,我使用了这种表示法:

        var predicate = PredicateExtensions.False<table2>();
        if (RegNos != null)
        {
            predicate = predicate.Or(ec => RegNos.Contains(ec.regno));
        }

我的问题是:

  1. 为什么使用foreach循环会发生堆栈溢出?

  2. 我认为Windows Server 2003的每个进程\线程的堆栈比NT \ 2000 \ XP \ Vista \ Windows 7工作站版本的Windows小得多。

  3. 使用LINQ和LINQKit实现此目的的最快,最正确的方法是什么?

  4. 有人建议我停止使用LINQ并返回动态SQL或ADO.NET,但我认为使用LINQ和LINQKit更易于维护。

3 个答案:

答案 0 :(得分:2)

非常古老的问题但是... LinqKit将使用递归并且堆栈将非常深:

OR(OR(OROR(OR(OR(OR(....)))))))

如果你的表达式在列表中,LinqKit有这个扩展方法AggregateBalanced,它将表达式平衡为二叉树:

OR(OR(OR(...), OR(...)),OR(OR(...), OR(...)))

所以在迭代之前调用它,递归级别更像是log n而不是n。

https://github.com/scottksmith95/LINQKit/blob/96626e863784bac5d324c5cb4b189f5cb902d1ab/src/LinqKit/AggregateBalanced.cs

答案 1 :(得分:1)

这里有几个问题。首先,封底下的L2S使用sp_execsql,一个SQL UDF。 SQL UDF最多可以传递2100个参数,IIRC,常量和比较总是作为参数发出。因此,即使表达式求值程序没有死亡,结果查询也不会运行。表达式求值程序可能会死亡,因为PredicateBuilder嵌套了添加的表达式,而L2S表达式求值程序以递归方式遍历表达式树。也许你可以将大型过滤器列表填入临时表并加入它?我相信设计器支持命名的临时表,或者您可以使用表值的sproc来插入过滤器值,然后使用L2S来完成繁重的工作。

答案 2 :(得分:0)

正如马特已经说过的,你的表达树可能太大了。请参阅我的博客文章,了解如何处理此问题。

http://kalcik.net/2014/01/05/joining-data-in-memory-with-data-in-database-table/