3

编辑#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;

    }

我的业务对象与 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 思维方式思考时会发生这种情况

4

3 回答 3

3

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

无论如何,在 StackOverflow 异常中检查堆栈总是有帮助的。如果您看到一个属性被反复访问,很可能是因为您正在执行以下操作:

公共对象 MyProperty { 设置 { MyProperty = 值;}}

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

于 2008-10-26T19:45:02.150 回答
1

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

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

于 2008-10-26T19:53:27.733 回答
1

要回答您编辑的问题,即:“在不触发无限循环的情况下将对象相互链接”:

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

选项1:

  • 获取所有国家/地区(将子区域留空)
  • 获取所有子区域(将国家留空)
  • 对于每个次区域,查看国家列表并将次区域添加到国家,将国家添加到次区域

选项 2:

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

(或反向国家和次区域)

它们基本上是等效的答案,只是在您进行一些链接时会发生变化。

于 2008-10-26T19:54:00.633 回答