LINQ 的嵌套组
Posted
技术标签:
【中文标题】LINQ 的嵌套组【英文标题】:Nested Group by LINQ 【发布时间】:2012-03-06 06:21:48 【问题描述】:我无法使用 LINQ 查询解决此问题。
所以我们的表结构如下: 编号 ||错误类别 ||错误名称 ||错误详细信息 || bug_priority
我想先按 bug_category 分组。对于每个 bug_category,我想依次按 bug__priority 分组。
所以基本上我想要类似的东西:
bug_category = AUDIO :: No of BUGS --> 严重 = 3,中等 = 2 和低 = 7 个错误。 bug_category = VIDEO :: No of BUGS --> 严重 = 5,中等 = 1 和低 = 9 个错误。
以下查询返回类别 AND customer_priority 的所有唯一组合:
(其中 RawDataList 只是具有上述结构的数据列表)
var ProceesedData = from d in RawDataList
group d by new d.bug_category, d.bug_priority into g
select new
g.Key.bug_category,
g.Key.bug_priority
;
以下查询返回类别,后跟该类别中的记录列表:
var ProceesedData = from d in RawDataList
group d by d.bug_category into g
select new g.Key, records = g
;
但我无法继续进行,因为 ProcessedData(返回变量)是未知类型。对此有什么想法吗?
【问题讨论】:
【参考方案1】:这是完成嵌套分组的一种更简单的方法。我已经在内存集合中对其进行了测试,您的特定数据库提供商是否能很好地处理它可能会有所不同,或者它是否表现良好是未知的。
假设您有两个属性,并且想按州和国家/地区分组:
var grouped = People
.GroupBy(l => new l.State, l.Country)//group by two things
.GroupBy(l=> l.Key.Country)//this will become the outer grouping
foreach(var country in grouped)
foreach(var state in country)
foreach(var personInState in state)
string description = $"Name: personInState.Name, State: state.StateCode, Country: country.CountryCode";
...
【讨论】:
这是一个很难找到的答案! 是的,当我自己需要这个时,我花了一段时间才弄清楚这一点,当我需要这样做时,我实际上会回到自己的答案。【参考方案2】:我怀疑你想要(名字改得更惯用了):
var query = from bug in RawListData
group bug by new bug.Category, bug.Priority into grouped
select new
Category = grouped.Key.Category,
Priority = grouped.Key.Priority,
Count = grouped.Count()
;
然后:
foreach (var result in query)
Console.WriteLine("0 - 1 - 2",
result.Category, result.Priority, result.Count);
或者(但见后文):
var query = from bug in RawListData
group bug by new bug.Category into grouped
select new
Category = grouped.Category,
Counts = from bug in grouped
group bug by grouped.Priority into g2
select new Priority = g2.Key, Count = g2.Count()
;
foreach (var result in query)
Console.WriteLine("0: ", result.Category);
foreach (var subresult in result.Counts)
Console.WriteLine(" 0: 1", subresult.Priority, subresult.Count);
编辑:如 cmets 中所述,这将导致多个 SQL 查询。要获得类似的结果结构但更有效,您可以使用:
var dbQuery = from bug in RawListData
group bug by new bug.Category, bug.Priority into grouped
select new
Category = grouped.Key.Category,
Priority = grouped.Key.Priority,
Count = grouped.Count()
;
var query = dbQuery.ToLookup(result => result.Category,
result => new result.Priority, result.Count ;
foreach (var result in query)
Console.WriteLine("0: ", result.Key);
foreach (var subresult in result)
Console.WriteLine(" 0: 1", subresult.Priority, subresult.Count);
【讨论】:
第二个查询将为每个组创建一个辅助查询,所以我认为更好的解决方案是第一个查询,然后是 ToLookup by category @AdrianIftode:你试过了吗?我没有,但我预计会生成适当的 SQL 以一次性完成所有操作。 是的,使用 LinqPad,一个查询类别组和其他 X 查询优先级组 @AdrianIftode:对 - 届时将对其进行编辑。我想知道在 EF 中是否会发生同样的事情...... 不,它在主要组和次要组之间进行外部应用(在外部应用连接中使用主要组键),因此在这种情况下为 EF +1(与许多其他情况一样)跨度> 【参考方案3】:我认为您正在搜索类似的内容:
var processedData =
rawData.GroupBy(bugs => bugs.bug_category,
(category, elements) =>
new
Category = category,
Bugs = elements.GroupBy(bugs => bugs.bug_priority,
(priority, realbugs) =>
new
Priority = priority,
Count = realbugs.Count()
)
);
foreach (var data in processedData)
Console.WriteLine(data.Category);
foreach (var element in data.Bugs)
Console.WriteLine(" " + element.Priority + " = " + element.Count);
【讨论】:
@Nandu:你意识到这与我的第二个查询基本相同,只是采用 lambda 表达式形式,对吧?请注意,它的性能与 Adrian 指出的相同(因为它是相同的查询)。 比 Jon Skeet 多花 9 分钟来写答案的危险 ;)【参考方案4】:你可以这样做
var retList = (from dbc in db.Companies
where dbc.IsVerified && dbc.SellsPCBs && !dbc.IsDeleted && !dbc.IsSpam && dbc.IsApproved
select new
name = dbc.CompanyName,
compID = dbc.CompanyID,
state = dbc.State,
city = dbc.City,
businessType = dbc.BusinessType
).GroupBy(k => k.state).ToList();
List<dynamic> finalList = new List<dynamic>();
foreach (var item in retList)
finalList.Add(item.GroupBy(i => i.city));
【讨论】:
以上是关于LINQ 的嵌套组的主要内容,如果未能解决你的问题,请参考以下文章