C# WinForms中如何使用LINQ从DataGridView查询多字段并分组统计
多字段LINQ分组统计实现方案
核心逻辑:多字段分组需要构造复合匿名类型作为分组键,不能单独传多个参数给分组方法。
场景1:双字段(页面+IP)访问次数统计
对应需求的SQL逻辑,正确实现代码如下:
// 所有页面访问量及对应访问IP统计 var pagesIPCountQuery = dataGridViewIISDateTime.Rows.Cast<DataGridViewRow>() .Where(r => r.Cells[5].Value != null && r.Cells[9].Value != null) // 构造包含两个字段的匿名对象作为处理单元 .Select(r => new { IP = r.Cells[5].Value.ToString(), Page = r.Cells[9].Value.ToString() }) // 把两个字段一起作为分组的复合键 .GroupBy(g => new { g.IP, g.Page }) // 按访问次数倒序 .OrderByDescending(g => g.Count()) // 输出绑定用的结果结构 .Select(g => new { IP_ADDRESS = g.Key.IP, PAGE = g.Key.Page, VISITS = g.Count() }).ToList(); dataGridView1.DataSource = pagesIPCountQuery;
原写法错误点:
- Select返回值没有用匿名类型包裹多个字段,语法不合法
- GroupBy参数错误,多字段分组需要把所有分组字段放在同一个匿名类型里作为唯一Key
- OrderByDescending单次只能接收一个排序字段,同时传两个参数不符合方法定义
场景2:三字段统计用户访问页面的500错误
正确实现代码如下:
var error500Query = dataGridViewIISDateTime.Rows.Cast<DataGridViewRow>() .Where(r => r.Cells[2].Value != null && r.Cells[2].Value.ToString() == "500" // 500筛选直接放在Where条件里提前过滤 && r.Cells[9].Value != null && r.Cells[11].Value != null) // 构造包含三个字段的匿名对象 .Select(r => new { Username = r.Cells[11].Value.ToString(), Page = r.Cells[9].Value.ToString(), HTTP_CODE = r.Cells[2].Value.ToString() }) // 三个字段作为复合分组键 .GroupBy(g => new { g.Username, g.Page, g.HTTP_CODE }) .OrderByDescending(g => g.Count()) .Select(g => new { USERNAME = g.Key.Username, PAGE = g.Key.Page, HTTP_CODE = g.Key.HTTP_CODE, HITS = g.Count() }).ToList(); dataGridView1.DataSource = error500Query;
原写法错误点:
- 把
r.Cells[2].Value.Equals("500")的布尔判断结果赋值给了HTTP字段,所以绑定到DataGridView后布尔值默认渲染为复选框 - 500错误的筛选逻辑应该放在Where条件里提前过滤非500的行,不需要放到Select里处理
- 未提前过滤的情况下全量数据分组会产生不必要的性能损耗
内容的提问来源于stack exchange,提问作者Luis
相关产品推荐
相关产品推荐

