Linq to sql 在联接中使用IQueryable会导致StackOverflow异常
有人知道这会导致stackoverflow异常的原因吗:Linq to sql 在联接中使用IQueryable会导致StackOverflow异常,linq-to-sql,Linq To Sql,有人知道这会导致stackoverflow异常的原因吗: public IQueryable<Category> LoadCategories(bool onlyCatsWithProducts, ...) { var db = new DbDataContext(); var res = db.Categories.AsQueryable(); if (onlyCatsWithProducts) res = from p in db.Pro
public IQueryable<Category> LoadCategories(bool onlyCatsWithProducts, ...)
{
var db = new DbDataContext();
var res = db.Categories.AsQueryable();
if (onlyCatsWithProducts)
res = from p in db.Products
from c in res
where p.CategoryID == c.ID
select c;
...
return res;
}
public IQueryable加载类别(仅限bool-ycatswithproducts,…)
{
var db=new DbDataContext();
var res=db.Categories.AsQueryable();
if(仅适用于ATSWITH产品)
res=从p开始,单位为db.乘积
从c到res
其中p.CategoryID==c.ID
选择c;
...
返回res;
}
更新
更改了示例代码,以明确为什么要分配给变量,然后在以后重新分配它。基本上,这是因为我正在编写一个函数,从数据库返回类别,并引入几个参数(例如,onlyCatsWithProducts),其中每个参数仅在结果集有值时过滤结果集。请注意,这仍然不是我的实际代码,因为我的查询更复杂,我只想显示重现错误所需的最简单查询。为什么要创建一个变量,然后在赋值中使用该变量直接重新赋值?您的查询可能正在执行某种无限递归,导致出现
StackOverFlowException
。尝试以下方法:
var res =
from c in DB.Instance.Categories
from p in DB.Instance.Products
where p.CategoryID == c.ID
select c;
更新:
试试下面的方法。我认为您需要避免在res
的赋值中使用res
IQueryable<Category> res;
if (onlyCatsWithProducts)
res = from p in db.Products
from c in db.Categories.AsQueryable()
where p.CategoryID == c.ID
select c;
IQueryable res;
if(仅适用于ATSWITH产品)
res=从p开始,单位为db.乘积
来自db.Categories.AsQueryable()中的c
其中p.CategoryID==c.ID
选择c;
抱歉,发布后我发现交换订单似乎可以解决问题。我不知道为什么:
var db = new DbDataContext();
var res = db.Categories.AsQueryable();
res = from c in res
from p in db.Products
where p.CategoryID == c.ID
select c;
Michael在回答自己的问题时说,他不知道为什么将他的
的顺序从
调换来解决了他的问题
这样会导致堆栈溢出:
var res = db.Categories.AsQueryable();
res = from p in db.Products
from c in res
where p.CategoryID == c.ID
select c;
像这样没有:
var res = db.Categories.AsQueryable();
res = from c in res
from p in db.Products
where p.CategoryID == c.ID
select c;
原因如下。编译器将上述两个查询转换为以下代码:
var res = db.Categories.AsQueryable();
var q = db.Products
.SelectMany(p => res, (p, c) => new { p, c })
.Where(x => x.p.CategoryID == x.c.ID)
.Select(x => x.c);
这分别是:
var res = db.Categories.AsQueryable();
var q = res
.SelectMany(c => db.Products, (c, p) => new { c, p })
.Where(x => x.p.CategoryID == x.c.ID)
.Select(x => x.c);
第一个包含lambdap=>res
,它基本上捕获了对res
变量的引用。由于res
每次在引用中运行查询时都会重新分配自身的重新分配版本和bang-stack溢出
在第二种情况下,res
在任何lamdba之外,因此不会捕获引用,只使用原始引用,即res=db.Categories.AsQueryable()
,并且在执行查询时不会更改
它可能同样易于使用:
var res = from c in db.Categories
from p in db.Products
where p.CategoryID == c.ID
select c;
我希望这有助于澄清正在发生的事情。这是实际代码吗?如果是这样的话,我猜是有一个拼写错误…什么是v?谢谢你修正了拼写错误。对于这个示例,我只是简化了很多代码,所以不是我的实际代码。您不应该需要
.AsQueryable()
。您可能希望尝试显式地将输出类型设置为基础接口,而不是使用var
或AsQueryable()
。我不确定在这里递归分配表达式树时,这是否能解决堆栈溢出问题。@JimWooley.AsQueryable()
的目的是因为db.Categories
的类型是System.Data.Linq.Table
,稍后我将System.Data.Linq.DataQuery
类型的查询分配给该变量。我当然可以将变量声明为IQueryable res=db.Categories代码>但这无助于修复错误。已更改问题以反映变量的用途。您的代码确实可以工作,但我的函数接受了许多参数(而不是像我澄清的示例中那样只有一个参数),这些参数根据传入的内容改变查询,因此在一个查询中完成所有操作将使查询变得更加复杂。如果这是应用的第一个过滤器,我可以这样做,但是我的三个过滤器有复杂的连接,需要这种语法,所以对于所有的排列,有很多if-else语句,这不是很好。