我正在使用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));
}
我的问题是:
为什么使用foreach循环会发生堆栈溢出?
我认为Windows Server 2003的每个进程\线程的堆栈比NT \ 2000 \ XP \ Vista \ Windows 7工作站版本的Windows小得多。
使用LINQ和LINQKit实现此目的的最快,最正确的方法是什么?
有人建议我停止使用LINQ并返回动态SQL或ADO.NET,但我认为使用LINQ和LINQKit更易于维护。
答案 0 :(得分:2)
非常古老的问题但是... LinqKit将使用递归并且堆栈将非常深:
OR(OR(OROR(OR(OR(OR(....)))))))
如果你的表达式在列表中,LinqKit有这个扩展方法AggregateBalanced
,它将表达式平衡为二叉树:
OR(OR(OR(...), OR(...)),OR(OR(...), OR(...)))
所以在迭代之前调用它,递归级别更像是log n而不是n。
答案 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/