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

时间:2010-04-20 15:05:36

标签: c# linq-to-sql stack-overflow linq-to-objects

我写了以下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'是一组ISOCountry对象,显式创建并作为IQueryable&lt; ISOCountry&gt;返回。 (ISOCountry只是两个字符串的对象,isoCountryCode和Name)。竞争对手是IQueryable&lt;竞争对手&gt;虽然我从头创建了对象并使用了LINQ数据映射装饰器,但它通过LINQ to SQL绑定到数据库表。

由于某种原因,当系统尝试执行时,此查询会导致堆栈溢出。我不知道为什么,我已经尝试修剪Distinct,使用'select c'返回两个字符串的匿名类型,但都会导致溢出。 e.CountryID值是从一个下拉列表中填充的,该下拉列表本身是从IQueryable&lt; ISOCountry&gt;填充的,所以我知道这些值是合适的,但即使不是,我也不希望堆栈溢出。

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

根据要求,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 个答案:

答案 0 :(得分:2)

也许我疯了,但你的实用工具类不应该输出一个IQueryable列表。您正在创建看起来像的本地序列,它应该是可查询的。最终,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()语句中使用。因此,如果要将本地序列与IQueryable序列“网格化”,则必须强制IQueryable触发SQL语句并从数据库中获取它所代表的记录。要做到这一点,你所要做的就是以某种方式迭代IQueryable记录:

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

一旦您从数据库中获取了记录,就可以创建ISOCountry记录列表。同样,由于此列表不是来自您的datacontext,因此它不应该是IQueryable列表。相反,试试这个:

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

这样可行,但您可能从数据库中获取不必要的记录。如果您可以将ISOCountry列表上传到数据库,那就更好了。一旦你这样做,你就可以在最初设想的时候触发查询。