Вопрос

изменить № 2: Вопрос решен наполовину.Смотри ниже

В качестве дополнительного вопроса: знает ли кто-нибудь ненавязчивый способ решить то, что я пытаюсь сделать ниже (а именно, связывание объектов друг с другом без запуска бесконечных циклов)?


Я пытаюсь создать веб-приложение asp.net-mvc и получаю исключение 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, поэтому я заполняю их новыми.

В 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))
               };
    }

Возможно, здесь придется подумать о чем-то еще :) Вот что происходит, когда вы думаете объектно-ориентированно из-за слишком большого количества кофе.

Это было полезно?

Решение

Проблема может заключаться в следующем: у стран есть субрегионы, а у субрегионов есть страны. Я не знаю, как вы реализуете ленивый список, но это может продолжать вызывать GetCountries, а затем GetSubRegions и так далее. Чтобы выяснить это, я бы запустил отладчик и установил точки останова в заголовках методов GetCountries и GetSubRegions.

Я пробовал похожие шаблоны с LinqToSql, но трудно заставить работать двунаправленную навигацию, не сильно влияя на производительность. Это одна из причин, по которой я сейчас использую NHibernate.

Другие советы

Хай!Я думаю, что ваши модели непреднамеренно рекурсивно вызывают метод, что приводит к переполнению стека.Например, ваш объект Subregion пытается получить объекты Country, которые, в свою очередь, должны получить Subregions.

В любом случае всегда полезно проверить стек в исключении StackOverflow.Если вы видите, что к свойству обращаются снова и снова, скорее всего, это потому, что вы делаете что-то вроде этого:

общественный объект MyProperty {set {MyProperty = значение;}}

Легче обнаружить ситуации, подобные вашей, когда метод A вызывает метод B, который вызывает метод A, потому что вы можете видеть, что одни и те же методы появляются в стеке вызовов два или более раз.

Чтобы ответить на ваш отредактированный вопрос, а именно:«связывание объектов друг с другом без запуска бесконечных циклов»:

Предположим, у вас есть какие-то отношения, в которых обе стороны должны знать друг о друге...получить все соответствующие объекты с обеих сторон, а затем связать их вместе, вместо того, чтобы пытаться заставить выборку одной стороны автоматически получать другую.Или просто сделай один сторону, возьмите другую, а затем исправьте оставшуюся.Итак, в вашем случае варианты будут такими:

Опция 1:

  • Выбрать все страны (субрегионы оставив пустыми).
  • Получить все субрегионы (оставив страны пустыми).
  • Для каждого субрегиона просмотрите список стран и добавьте субрегион к стране и страну к субрегиону.

Вариант 2:

  • Выбрать все страны (субрегионы оставив пустыми).
  • Получите все субрегионы, установив Subregion.Countries через список стран, полученный выше.
  • Для каждого субрегиона просмотрите все входящие в него страны и добавьте его в эту страну.

(Или поменяйте местами страну и субрегион)

По сути, это эквивалентные ответы, просто они меняются, когда вы делаете некоторые ссылки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top