使用字典在 DataTable 上动态构建条件

Dynamically build a condition on a DataTable using a Dictionary

目前我可以这样查询我的 DataTable (dtContacts): 如果我正在寻找 FirstName 是 "John" 且 LastName 是 "Smith" 的人。我的结果将是

DataTable dt = dtContacts.AsEnumerable().Where(c => c.Field<string>("FirstName") == "John" && c.Field<string>("LastName") == "Smith").CopyToDataTable();

但是这样的静态查询对我没有帮助,因为我的情况可能比这稍微复杂一些。所以我希望我的 LINQ 更动态一点,以便它可以适应以下场景。

我将像这样在 Dictionary<string,string> 中保存我的条件:

Dictionary<string, string> dicConditions = new Dictionary<string, string>();
dicConditions.Add("FirstName", "John");
dicConditions.Add("LastName", "Smith");
dicConditions.Add("IsCustomer", "Yes");

请注意,我们可以向该词典中添加任意数量的条件。 并且假设主 DataTable dtContacts 始终包含字典键中提到的列名,因此我们不需要每次都检查它。

在新版本中,我们希望我们的 LINQ 根据 dicConditions 和 return 所有 FirstName 为 "John"、LastName 的值进行操作是 "Smith" 而 IsCustomer 是 "Yes".

这个新的动态 LINQ 查询应该是什么样子?

你可以这样做:

DataTable dt = dtContacts
    .AsEnumerable()
    .Where(c => 
        dicConditions.All(kv => c.Field<string>(kv.Key) == kv.Value)
    ).CopyToDataTable();

想法是应用 LINQ 两次 - 一次应用到 dtContacts,一次应用到 Where 子句内的 dicConditions

您可以使用如下方法从字典构建上面显示的谓词:

using StringKvp = System.Collections.Generic.KeyValuePair<string, string>;
using DataRowPredicate = System.Func<System.Data.DataRow, bool>;
...

var pred = dicConditions.Aggregate<StringKvp, DataRowPredicate>(r => true,
    (net, curr) => r => net(r) && r.Field<string>(curr.Key) == curr.Value);

然后只需使用此谓词过滤您的集合即可:

var dt = dtContacts.AsEnumerable().Where(pred).CopyToDataTable();

像这样...

var result= dtContacts.Rows.OfType<DataRow>().Where(r=>dicConditions.All(d=>r[d.key]==d.Value));

您可能需要正确转换字典的值以与数据表兼容...
使用 Regex 支持通配符...等...