在ASP.NET C#中使用LINQ计算DataTable的Sum列差值及关联场景实现
我来帮你搞定这两个在ASP.NET C#里用LINQ操作DataTable的问题,直接上实用方案:
问题1:计算DataTable中Sum(列1) - Sum(列2)的结果
要实现这个需求,核心是先把DataTable转成可枚举的行集合(用AsEnumerable()方法),然后分别计算两列的总和再做减法。这里要注意数据类型的选择,尤其是处理金额类数据时,优先用decimal避免精度丢失。
示例代码:
// 假设你的DataTable名为dt,列名是"Column1"和"Column2" if (dt != null && dt.Rows.Count > 0) { // 计算两列的总和 var sumColumn1 = dt.AsEnumerable().Sum(r => r.Field<decimal>("Column1")); var sumColumn2 = dt.AsEnumerable().Sum(r => r.Field<decimal>("Column2")); // 得到最终结果 var result = sumColumn1 - sumColumn2; // 后续可以用result做输出、赋值等操作 Console.WriteLine($"计算结果:{result}"); }
如果你的列是int或double类型,只需要把Field<decimal>改成对应的Field<int>或Field<double>就行,但还是推荐用decimal处理财务相关数据。
问题2:给datdetail的「Opening Balance」列批量赋值
你的需求是遍历datdetail每一行,根据当前行的「Identity ID」和指定日期,在DatTemp表中筛选符合条件的行,计算Sum(Dr)-Sum(Cr)后赋值给「Opening Balance」。我先补全你给出的代码,再给你一个性能更优的版本。
基础实现(补全你的代码)
先把日期转换提出来避免重复操作,然后完成计算逻辑:
// 先把TxtFromDate的日期转成DateTime类型,避免循环里重复转换 DateTime fromDate = Convert.ToDateTime(TxtFromDate.Text.Trim()); for (int i = 0; i < datDetail.Rows.Count; i++) { int currentIdentityId = Convert.ToInt32(datDetail.Rows[i]["Identity ID"]); // 筛选符合条件的行,分别计算Dr和Cr的总和 var totalDr = DatTemp.AsEnumerable() .Where(r => r.Field<int>("Identity ID") == currentIdentityId && r.Field<DateTime>("Date") <= fromDate) .Sum(r => r.Field<decimal>("Dr")); var totalCr = DatTemp.AsEnumerable() .Where(r => r.Field<int>("Identity ID") == currentIdentityId && r.Field<DateTime>("Date") <= fromDate) .Sum(r => r.Field<decimal>("Cr")); // 赋值给Opening Balance列 datDetail.Rows[i]["Opening Balance"] = totalDr - totalCr; }
性能优化版本
上面的写法虽然能实现需求,但如果DatTemp和datdetail的行数较多,每次循环都要遍历整个DatTemp,性能会很差。咱们可以提前缓存DatTemp的分组结果,减少重复遍历:
// 先验证日期输入合法性,避免转换异常 if (!DateTime.TryParse(TxtFromDate.Text.Trim(), out DateTime fromDate)) { // 这里可以加用户提示,比如"请输入正确的日期格式" return; } // 提前处理DatTemp,按Identity ID分组并缓存截止日期前的Dr、Cr总和 var balanceCache = DatTemp.AsEnumerable() .Where(r => r.Field<DateTime>("Date") <= fromDate) .GroupBy(r => r.Field<int>("Identity ID")) .ToDictionary( group => group.Key, group => new { TotalDr = group.Sum(r => r.Field<decimal>("Dr")), TotalCr = group.Sum(r => r.Field<decimal>("Cr")) } ); // 遍历datdetail赋值,直接从缓存取数据 foreach (DataRow row in datDetail.Rows) { int identityId = Convert.ToInt32(row["Identity ID"]); decimal openingBalance = 0; // 用TryGetValue避免找不到对应ID时的异常 if (balanceCache.TryGetValue(identityId, out var balanceData)) { openingBalance = balanceData.TotalDr - balanceData.TotalCr; } row["Opening Balance"] = openingBalance; }
优化点说明
- 只遍历一次DatTemp,把结果缓存到字典里,后续直接查询字典,时间复杂度从O(n*m)降到O(n+m)(n是DatTemp行数,m是datdetail行数)
- 用
foreach遍历DataRow比for循环更简洁直观 - 加了
DateTime.TryParse处理日期格式错误的情况,代码更健壮 - 用
TryGetValue避免找不到对应Identity ID时抛出异常
内容的提问来源于stack exchange,提问作者gurmeet singh
相关产品推荐
相关产品推荐

