代码之家  ›  专栏  ›  技术社区  ›  Lazarus

在我的LINQ查询中跟踪堆栈溢出错误

  •  4
  • Lazarus  · 技术社区  · 14 年前

    我已经写了以下内容 LINQ 查询:

    IQueryable<ISOCountry> entries =
      (from e in competitorRepository.Competitors
       join c in countries on e.countryID equals c.isoCountryCode
       where !e.Deleted
       orderby c.isoCountryCode
       select new ISOCountry() { isoCountryCode = e.countryID, Name = c.Name }
      ).Distinct();
    

    其目标是检索系统中竞争对手所代表的国家列表。Countries是一个等国家对象数组,显式创建并返回为iQuery<isocountry>(等国家对象只有两个字符串,即isocountrycode和name)。竞争对手是iqueryable<competitor>,它通过 LINQ to SQL 尽管我从头开始创建对象,并使用了Linq数据映射装饰器。

    由于某种原因,当系统尝试执行该查询时,该查询会导致堆栈溢出。我不知道为什么,我尝试了修剪distinct,返回两个字符串的匿名类型,使用“select c”,但都会导致溢出。e.countryID值是从一个下拉列表填充的,该下拉列表本身是从iqueryable<isocountry>填充的,因此我知道这些值是适当的,但即使不是,我也不会期望堆栈溢出。

    为什么会发生溢出,或者为什么会发生溢出?

    根据要求,等国家代码:

    public class ISOCountry
    {
        public string isoCountryCode { get; set; }
        public string Name { get; set; }
    }
    

    它是从静态实用程序类初始化的,因此:

        public static IQueryable<ISOCountry> GetCountryCodes()
        {
            // ISO 3166-1 country names and codes from http://opencountrycodes.appspot.com/javascript
            ISOCountry[] countries = new ISOCountry[] {
                new ISOCountry { isoCountryCode= "AF", Name= "Afghanistan"},
                new ISOCountry { isoCountryCode= "AX", Name= "Aland Islands"},
                new ISOCountry { isoCountryCode= "AL", Name= "Albania"},
                new ISOCountry { isoCountryCode= "DZ", Name= "Algeria"},
                new ISOCountry { isoCountryCode= "AS", Name= "American Samoa"},
                ...
                new ISOCountry { isoCountryCode= "YE", Name= "Yemen"},
                new ISOCountry { isoCountryCode= "ZM", Name= "Zambia"},
                new ISOCountry { isoCountryCode = "ZW", Name = "Zimbabwe"}
            };
            return countries.AsQueryable();
        }
    

    我最终如何让它发挥作用,见下文…我仍然好奇原始查询的具体问题,我确信我以前做过类似的事情。

    IList<string> entries = competitorRepository.Competitors.Select(c=>c.CountryID).Distinct().ToList();
    IList<ISOCountry> countries = Address.GetCountryCodes().Where(a => entries.Contains(a.isoCountryCode)).ToList();
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Peter Mortensen Len Greski    12 年前

    也许我疯了,但你的实用程序类不应该输出一个可查询的列表。您正在创建一个本地序列, 看起来像 它应该是可查询的。最后,IQueryable列表应该由DataContext挖掘出来。如果一个实用程序类正在创建一个列表,那么它应该作为数组或IEnumerable返回,例如:

        public static readonly ISOCountry[] CountryCodes = new ISOCountry[] {
            new ISOCountry { isoCountryCode= "AF", Name= "Afghanistan"},
            new ISOCountry { isoCountryCode= "AX", Name= "Aland Islands"}
            ...
        };
    

    局部序列只能在iqueryable.contains()语句中使用。因此,如果要用iQuery序列“网格化”本地序列,则必须强制iQuery触发SQL语句并从数据库中获取其表示的记录。要做到这一点,您所要做的就是以某种方式迭代IQueryable记录:

    IList<Competitor> competitorRecords =  competitorRepository
       .Competitors
       .Where(m => !m.Deleted)
       .OrderBy(m => m.countryId)
       .ToList(); //This fires the SQL statement
    

    一旦您从数据库中捕获了这些记录,就可以创建等国家记录的列表。同样,由于此列表不是来自您的DataContext,因此它不应该是iQuery列表。相反,请尝试以下操作:

    IList<ISOCountry> = competitorRecords
        .Join(CountryCodes, key1 => key1.countryId, key2 => key2.isoCountryCode, (competitors, codes) => new ISOCountry { isoCountryCode = competitors.countryId, Name = codes.Name })
        .ToList();
    

    这将有效,但您可能会从数据库中获取不必要的记录。如果你能把你的等国家列表上传到数据库中,那就更好了。一旦您这样做了,您就能够像最初设想的那样启动查询。