我有一个代码,用于在数据表中搜索特定字符串,并根据特定条件(唯一id字段)返回整个数据表的子集。下面的示例代码搜索" First"和"员工"在数据表中,只返回那些具有相同l_id值的条目。
//Get all Id's that satisfy all conditions:
List<int> results = dtResult.AsEnumerable()
// Get all Id's:
.Select(dataRow => dataRow.Field<int>("l_id"))
// Filter the Id's :
.Where(id =>
// the Id should be greater than one.
id > 1
// and the datatable rows with this Id should have a record with W_Text = First
&& dtResult.AsEnumerable().Any(dataRow => dataRow.Field<string>("W_Text") == "First" && dataRow.Field<int>("l_id") == id)
// and the datatable rows with this Id should have a record with W_Text = Employee
&& dtResult.AsEnumerable().Any(dataRow => dataRow.Field<string>("W_Text") == "Employee" && dataRow.Field<int>("l_id") == id))
.Distinct().ToList();
// Get all datatable rows filtered by the list of Id's.
dtCopy = dtResult.AsEnumerable().Where(dataRow => results.Contains((dataRow.Field<int>("l_id")))).CopyToDataTable();
现在,如果我动态获取搜索文本,那么我该如何处理呢? 对于。例如,在上面的代码中,如果我必须通过&#34; First&#34;以及&#34;员工&#34;以及&#34;薪水&#34;那我该怎么办?
如何制作此通用名称?
预先感谢您的协助!
编辑 - 看起来我的帖子里还没有明确,所以让我再说一遍
我有一个看起来像这样的数据表
l | t | r | b | x | y | w_text | l_id
-------------------------------------------------------------
70 | 314 | 141 | 328 | 1 | 5 | First | 4
149 | 318 | 194 | 328 | 2 | 5 | Employe| 4
204 | 311 | 254 | 326 | 3 | 5 | John | 4
264 | 311 | 325 | 326 | 4 | 5 | Smith | 4
1924 | 310 | 2000 | 329 | 5 | 5 | First | 5
70 | 341 | 109 | 355 | 1 | 6 | step | 5
115 | 340 | 130 | 355 | 2 | 6 | of | 5
136 | 340 | 175 | 355 | 3 | 6 | Linq | 5
185 | 339 | 320 | 356 | 4 | 6 | Last | 6
70 | 394 | 101 | 411 | 1 | 8 | Employe| 6
114 | 390 | 199 | 405 | 2 | 8 | John | 6
210 | 390 | 269 | 405 | 3 | 8 | Doe | 6
我手上唯一的搜索条件是&#39; W_Text&#39;。所以我想搜索一下唯一的短语&#34; First Employee&#34;。只有一个l_id(在这种情况下) l_id = 4)会有两个单词&#34; First&#34;以及&#34;员工&#34;。如果我搜索&#34;第一&#34;单独和&#34;员工&#34;单独,然后我会得到一个更大的数据集,这不解决我的目的。我的目标是在搜索&#34; First Employee&#34;
时获取以下唯一数据集l | t | r | b | x | y | w_text | l_id
-------------------------------------------------------------
70 | 314 | 141 | 328 | 1 | 5 | First | 4
149 | 318 | 194 | 328 | 2 | 5 | Employe| 4
204 | 311 | 254 | 326 | 3 | 5 | John | 4
264 | 311 | 325 | 326 | 4 | 5 | Smith | 4
在SQL术语中,这类似于
Select * From Table where l_id in (Select l_id from Table where W_Text in ('First','Employee') group by l_id having count(l_id) > 1)
上面提到的代码(由一位优秀的撒玛利亚人帮助过)完全正常,并返回上面的数据集。问题是它只适用于&#34; First Employee&#34;。我在查找说&#34; Linq&#34;的第一步时遇到了麻烦。搜索短语在运行时传递给程序,可以是多少个单词。我试过分离Wheres但是有'&#39;条件未命中,也是返回整个数据集的位置。
因此,我请求大家帮助我解决这个问题。我对Linq很新,我正努力工作。与此同时,我能得到的任何帮助都将受到高度赞赏。感谢。
---编辑使用此代码(有人的帮助)使其工作
List<string> wTextFilter = new List<string>();
foreach (string sf in strInputString.Split(' ')) //array by splitting on white space
{
wTextFilter.Add(sf);
}
// Get all Id's that satisfy all conditions:
List<int> results = dtResult.AsEnumerable()
// Get all Id's:
.Select(dataRow => dataRow.Field<int>("l_id"))
// Filter the Id's :
.Where(id =>
// the Id should be greater than one.
id > 1 &&
// check if all W_Text entries has a record in the datatable with the same Id.
wTextFilter.All(W_Text => dtResult.AsEnumerable().Any(dataRow => dataRow.Field<string>("W_Text") == W_Text && dataRow.Field<int>("l_id") == id)))
.Distinct().ToList();
// Get all datatable rows filtered by the list of Id's.
dtCopy = dtResult.AsEnumerable().Where(dataRow => results.Contains((dataRow.Field<int>("l_id")))).CopyToDataTable();
答案 0 :(得分:2)
您的代码几乎没有问题:
您在过滤之前选择了ID 。这意味着您最终得到int
s的集合,这意味着您无法再按另一列过滤。您应该过滤然后选择所需的列
您无需进行最终检查以查看列l_id
。我们已经检查了l_id == id
,显然列存在
您当前的查询不正确。如果数据集中的任何行匹配,则返回该行:
dtResult.AsEnumerable().Any(dataRow => dataRow.Field<string>("W_Text") == "First" && dataRow.Field<int>("l_id") == id)
这表示,对于每一行,检查是否有匹配的任何行。如果是这样,请返回该行。您的查询将返回整个数据集,或者不返回任何内容。
您可以链接.Where()
子句。例如:
public List<int> DoIt(int id, params string[] searchFor)
{
var results = dtResult.AsEnumerable()
// Filter the Id's :
.Where(dr => dr.id > 1)
.Where(dr => dr.Field<int>("l_id") == id);
foreach (var sf in searchFor)
results = results.Where(dr => dr.Field<string>("W_Text") == sf);
results = results.Select(dataRow => dataRow.Field<int>("l_id"))
return results.Distinct().CopyToDataTable();
}
答案 1 :(得分:1)
从您的基本条款开始:
results = results.Where(id => id > 1);
然后根据需要动态添加子句:
if (/**some condition**/)
results = results.Where(id => dtResult.AsEnumerable().Any(dataRow => dataRow.Field<string>("W_Text") == "First" && dataRow.Field<int>("l_id") == id));
if (/**another condition**/)
results = results.Where(id => dtResult.AsEnumerable().Any(dataRow => dataRow.Field<string>("W_Text") == "Employee" && dataRow.Field<int>("l_id") == id))
等等。对于要动态添加的每个条件,请添加新的.Where()
子句。您可以根据需要链接尽可能多的这些内容,从逻辑上讲,它可以与单个&&
中的一系列.Where()
子句相同。
答案 2 :(得分:0)
这是更接近您的SQL子查询的内容:
var q = dtResult.AsEnumerable() // from Table
.Where(r => new[] { "First", "Employee" }.Contains(r["W_Text"])) // where W_Text in ('First','Employee')
.GroupBy(r => (int)r["l_id"]) // group by l_id
.Where(g => g.Count() > 1) // having count(l_id) > 1
.Select(g => g.Key); // Select l_id
这是一个更高效的版本:
var words = new HashSet<string> { "First", "Employee" }; // optional HashSet instead of List for a bit faster .Contains
int iId = dtResult.Columns.IndexOf("l_id");
int iText = dtResult.Columns.IndexOf("W_Text");
var iRows = dtResult.Rows.Cast<DataRow>(); // a bit faster than dtResult.AsEnumerable()
var results = new HashSet<int>( // optional HashSet instead of List for faster .Contains
iRows
.Where(r => words.Contains(r[iText])) // filter the rows that contain the words
.ToLookup(r => (int)r[iId]) // group by l_id
.Where(g => g.Count() >= words.Count) // filter the groups that contain all words
.Select(g => g.Key) // select l_id
);
var dtCopy = iRows.Where(r => results.Contains((int)r[iId])).CopyToDataTable(); // InvalidOperationException if no DataRows
但是如果所有数据都已存在于DataTable中,那么您只需按l_id
分组并获取包含所有字词的组:
string[] words = { "First", "Employee" };
int iId = dtResult.Columns.IndexOf("l_id");
int iText = dtResult.Columns.IndexOf("W_Text");
var iRows = dtResult.Rows.Cast<DataRow>();
var idGroups = iRows.ToLookup(r => (int)r[iId]); // group by id
var result = idGroups.Where(g => !words.Except(g.Select(r => r[iText] as string)).Any());
var dtCopy = result.SelectMany(g => g).CopyToDataTable();