Laz*_*rus 5 c# stack-overflow linq-to-objects linq-to-sql
我编写了以下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();
Run Code Online (Sandbox Code Playgroud)
目标是检索系统中找到的竞争对手所代表的国家/地区列表。'countries' 是显式创建的 ISOCountry 对象数组,并作为 IQueryable<ISOCountry> 返回(ISOCountry 是只有两个字符串的对象,isoCountryCode 和 Name)。Competitors 是一个 IQueryable<Competitor>,它通过LINQ to SQL绑定到数据库表,尽管我从头开始创建对象并使用 LINQ 数据映射装饰器。
出于某种原因,当系统尝试执行该查询时,该查询会导致堆栈溢出。我不知道为什么,我尝试修剪 Distinct,使用 'select c' 返回两个字符串的匿名类型,但都导致溢出。e.CountryID 值是从下拉列表中填充的,该下拉列表本身是从 IQueryable<ISOCountry> 填充的,所以我知道这些值是合适的,但即使不是,我也不希望堆栈溢出。
为什么会发生溢出或为什么会发生?
根据要求,ISOCountry 的代码:
public class ISOCountry
{
public string isoCountryCode { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
它是从静态实用程序类初始化的,因此:
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();
}
Run Code Online (Sandbox Code Playgroud)
我是如何最终让它工作的,见下文......我仍然很好奇原始查询的具体问题,我确定我以前做过类似的事情。
IList<string> entries = competitorRepository.Competitors.Select(c=>c.CountryID).Distinct().ToList();
IList<ISOCountry> countries = Address.GetCountryCodes().Where(a => entries.Contains(a.isoCountryCode)).ToList();
Run Code Online (Sandbox Code Playgroud)
也许我疯了,但你的实用程序类不应该输出 IQueryable 列表。您正在创建一个看起来应该可查询的本地序列。最终,IQueryable 列表应该由您的数据上下文来挖掘。如果实用程序类正在创建列表,则应(最有可能)以数组或 IEnumerable 形式返回,例如:
public static readonly ISOCountry[] CountryCodes = new ISOCountry[] {
new ISOCountry { isoCountryCode= "AF", Name= "Afghanistan"},
new ISOCountry { isoCountryCode= "AX", Name= "Aland Islands"}
...
};
Run Code Online (Sandbox Code Playgroud)
本地序列只能在 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
Run Code Online (Sandbox Code Playgroud)
从数据库中获取记录后,您可以创建 ISOCountry 记录列表。同样,由于此列表不是来自您的数据上下文,因此它不应该是 IQueryable 列表。相反,试试这个:
IList<ISOCountry> = competitorRecords
.Join(CountryCodes, key1 => key1.countryId, key2 => key2.isoCountryCode, (competitors, codes) => new ISOCountry { isoCountryCode = competitors.countryId, Name = codes.Name })
.ToList();
Run Code Online (Sandbox Code Playgroud)
这可行,但您可能会从数据库中获取不必要的记录。如果您可以将 ISOCountry 列表上传到数据库,那就更好了。完成此操作后,您就可以按照最初设想的方式触发查询。
| 归档时间: |
|
| 查看次数: |
542 次 |
| 最近记录: |