场景一:多层分组转 Dictionary
把 DataTable 按多个字段分组,再按子字段二次分组并求和,最终得到一个两层嵌套的字典结构。
var list = dt2.AsEnumerable()
.GroupBy(p => new
{
ywrq = p.Field<string>("ywrq"),
xmmc = p.Field<string>("xmmc"),
ryxzmc = p.Field<string>("ryxzmc")
})
.ToDictionary(
p => p.Key,
p => p.GroupBy(x => new { sffsmc = x.Field<string>("sffsmc") })
.ToDictionary(
x => x.Key,
x => x.Sum(r => r.Field<decimal>("je"))
)
);Code language: JavaScript (javascript)
结果结构:
Dictionary<
外层Key (ywrq, xmmc, ryxzmc),
Dictionary<
内层Key (sffsmc),
decimal (je 求和)
>
>
访问方式:
// 取某个分组下某个收费方式的金额
var je = list[outerKey][innerKey];Code language: PHP (php)
场景二:按分组 Key 在 DataTable 中查找匹配行
分组后拿到 Key,需要回原 DataTable 中找到匹配的原始行。
DataRow row = dt.AsEnumerable()
.Where(m => m.Field<string>("ywrq") == item.Key.ywrq
&& m.Field<string>("xmmc") == item.Key.xmmc
&& m.Field<string>("ryxzmc") == item.Key.ryxzmc)
.FirstOrDefault();Code language: JavaScript (javascript)
说明:
| 写法 | 说明 |
|---|---|
AsEnumerable() | 把 DataTable 转为 IEnumerable<DataRow> |
Field<T>("列名") | 类型安全地读取列值,支持可空类型 |
FirstOrDefault() | 返回第一条匹配行,无匹配返回 null |
| 匿名对象 Key 对比 | 匿名对象按属性值逐个比较,所有字段相等则视为同一 Key |
关键要点
| 要点 | 说明 |
|---|---|
Field<T> | 读取 DataRow 列值,比 row["列名"] 更安全,支持可空类型 |
| 匿名对象作 Key | 自动实现 Equals 和 GetHashCode,适合分组和查找 |
多层 ToDictionary | 外层分组 → 内层子分组 → 聚合值 |
FirstOrDefault | 查找不到返回 null,需判空再使用 |
| 性能 | Where 逐行扫描,数据量大时考虑先 ToDictionary 建索引 |
建索引优化(数据量大时):
// 先建索引,避免多次扫描
var index = dt.AsEnumerable()
.GroupBy(m => new
{
ywrq = m.Field<string>("ywrq"),
xmmc = m.Field<string>("xmmc"),
ryxzmc = m.Field<string>("ryxzmc")
})
.ToDictionary(g => g.Key, g => g.First());
// 直接按 Key 取
DataRow row = index[item.Key];Code language: JavaScript (javascript)
Previous: ExecuteQuery 参数化查询中字符串不需要加单引号