由linq查询引起的StackOverflowException

时间:2008-10-26 19:30:03

标签: asp.net-mvc linq stack-overflow

编辑#2:问题解决了一半。看下面

作为一个后续问题,有没有人知道一种非侵入性的方法来解决我在下面尝试做的事情(即,在不触发无限循环的情况下将对象链接到彼此)?


我尝试创建一个asp.net-mvc Web应用程序,并获得StackOverFlowException。控制器触发以下命令:

    public ActionResult ShowCountry(int id)
    {
        Country country = _gameService.GetCountry(id);
        return View(country);
    }

GameService像这样处理它(WithCountryId是扩展名):

    public Country GetCountry(int id)
    {
        return _gameRepository.GetCountries().WithCountryId(id).SingleOrDefault();
    }

GameRepository像这样处理它:

    public IQueryable<Country> GetCountries()
    {
        var countries =  from c in _db.Countries
               select new Country
               {
                   Id = c.Id,
                   Name = c.Name,
                   ShortDescription = c.ShortDescription,
                   FlagImage = c.FlagImage,
                   Game = GetGames().Where(g => g.Id == c.GameId).SingleOrDefault(),
                   SubRegion = GetSubRegions().Where(sr => sr.Id == c.SubRegionId).SingleOrDefault(),
               };
        return countries;
    }

GetGames()方法导致StackOverflowException:

    public IQueryable<Game> GetGames()
    {
        var games = from g in _db.Games                   
               select new Game
               {
                   Id = g.Id,
                   Name = g.Name

               };
        return games;

    }

My Business对象与linq2sql类不同,这就是我用select new填充它们的原因。

mscorlib.dll中出现未处理的“System.StackOverflowException”类型异常


编辑#1:我找到了罪魁祸首,它是以下方法,它会触发GetCountries()方法,该方法又会再次触发GetSubRegions(),令人作呕:

    public IQueryable<SubRegion> GetSubRegions()
    {
        return from sr in _db.SubRegions
               select new SubRegion
               {
                   Id = sr.Id,
                   Name = sr.Name,
                   ShortDescription = sr.ShortDescription,
                   Game = GetGames().Where(g => g.Id == sr.GameId).SingleOrDefault(),
                   Region = GetRegions().Where(r => r.Id == sr.RegionId).SingleOrDefault(),
                   Countries = new LazyList<Country>(GetCountries().Where(c => c.SubRegion.Id == sr.Id))
               };
    }

可能必须在这里想到别的东西:)当你因为过多的咖啡而在OO心态中思考时会发生什么

3 个答案:

答案 0 :(得分:2)

海!我认为你的模型是无意中递归调用一个方法,这会导致堆栈溢出。例如,您的Subregion对象正在尝试获取Country对象,而这些对象又必须获取Subregions。

无论如何,在StackOverflow异常中检查堆栈总是有帮助的。如果你看到一次又一次地访问一个属性,很可能是因为你正在做这样的事情:

公共对象MyProperty {set {MyProperty = value; }}

更容易发现像你这样的情况,方法A调用方法B调用方法A,因为你可以看到在调用堆栈中出现两次或多次相同的方法。

答案 1 :(得分:1)

问题可能是:国家有次区域,次区域有国家。我不知道你是如何实现惰性列表的,但是可能会继续调用GetCountries,然后调用GetSubRegions等等。为了找到它,我将在GetCountries和GetSubRegions方法头上启动调试器设置断点。

我尝试使用LinqToSql的类似模式,但很难在不影响性能的情况下进行双向导航。这就是我现在正在使用NHibernate的原因之一。

答案 2 :(得分:1)

回答您编辑过的问题,即:“将对象链接到彼此而不触发无限循环”:

假设你有某种关系,双方都需要了解另一方......掌握双方所有相关实体,然后将它们联系在一起,而不是试图取得一面自动获取另一个。或者只是让一个方获取另一个,然后修复剩下的一个。因此,在您的情况下,选项将是:

选项1:

  • 获取所有国家/地区(将子区域留空)
  • 获取所有子区域(将国家/地区留空)
  • 对于每个分区域,查看国家清单并将分区域添加到国家和分区域的国家

选项2:

  • 获取所有国家/地区(将子区域留空)
  • 获取所有子区域,通过上面提取的国家/地区列表
  • 设置Subregion.Countries
  • 对于每个次区域,浏览所有国家/地区并将其添加到该国家/地区

(或反向国家和次区域)

它们基本上是等式答案,只是在你进行某些链接时会发生变化。