如何在C#中简洁筛选DataTable?处理VoidDate列筛选场景
问题解答
核心选择:复制后筛选更安全
直接修改原DataTable存在潜在风险——如果该DataTable还被其他代码引用,删除行的操作会意外影响其他逻辑。因此优先复制一份新的DataTable再执行筛选,避免产生副作用。
简洁实现方式
方法1:利用DataView.RowFilter(传统DataTable操作风格)
这种方式代码简洁,借助DataView的过滤能力生成新表:
public static DataTable GetInvoicesDataTable(string checkNo, int assocBankAcctID, int assocAcctLedgerID, int actionItemID, bool fetchAllItems, bool isUnvoid) { string sql = string.IsNullOrEmpty(checkNo) && !fetchAllItems ? GetSingleRecordQuery() : GetMultipleRecordQuery(checkNo, fetchAllItems); DataTable dt = DB.RtnTable(sql, DB.DB_CUSTOMER_DATA, assocBankAcctID, checkNo, actionItemID, assocAcctLedgerID); // 复制原表的结构与数据 DataTable filteredDt = dt.Copy(); if (isUnvoid) { // 保留VoidDate为null的行(排除非null记录) filteredDt.DefaultView.RowFilter = "VoidDate IS NULL"; } else { // 保留VoidDate不为null的行(排除null记录) filteredDt.DefaultView.RowFilter = "VoidDate IS NOT NULL"; } // 将过滤后的DataView转换为DataTable返回 return filteredDt.DefaultView.ToTable(); }
方法2:使用LINQ查询(现代C#风格)
如果项目支持LINQ to DataSet,代码逻辑会更直观:
using System.Linq; using System.Data; public static DataTable GetInvoicesDataTable(string checkNo, int assocBankAcctID, int assocAcctLedgerID, int actionItemID, bool fetchAllItems, bool isUnvoid) { string sql = string.IsNullOrEmpty(checkNo) && !fetchAllItems ? GetSingleRecordQuery() : GetMultipleRecordQuery(checkNo, fetchAllItems); DataTable dt = DB.RtnTable(sql, DB.DB_CUSTOMER_DATA, assocBankAcctID, checkNo, actionItemID, assocAcctLedgerID); IEnumerable<DataRow> filteredRows; if (isUnvoid) { filteredRows = dt.AsEnumerable().Where(row => row.IsNull("VoidDate")); } else { filteredRows = dt.AsEnumerable().Where(row => !row.IsNull("VoidDate")); } // 将筛选后的行集合转为新的DataTable return filteredRows.CopyToDataTable(); }
补充说明
- 若能确保原DataTable不会被其他代码引用,也可直接修改原表(比如用
dt.Rows.Remove批量删除不符合条件的行),但这种方式风险较高,不推荐。 - LINQ方式在.NET Framework中需要添加
System.Data.DataSetExtensions引用,.NET Core/.NET 5+版本默认包含该引用。
内容的提问来源于stack exchange,提问作者CarlosG90
相关产品推荐
相关产品推荐

