2017-02-14 69 views
-1

「其中」條款我有搜索特定字符串的數據表,並返回基於特定條件(唯一ID字段)的整個數據表的子集的代碼。以下示例代碼在數據表中搜索「First」和「Employee」,並僅返回具有相同l_id值的條目。動態構建Linq中

//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(); 

現在,如果我已經動態地獲取搜索文本,那麼該如何處理? 。例如,在上面的代碼中,如果我必須通過「第一」以及「員工」和「薪水」,那麼我該如何繼續?

我怎樣才能讓這個通用?

預先感謝您的幫助!

編輯 - 貌似我沒有在我的崗位明確,所以讓我重新整理再次

我有一個DataTable,它看起來像這樣

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 

在我手上唯一的搜索條件我有是「W_Text'.So我想尋找說獨特的短語‘第一員工’。只有一個l_id(在這種情況下l_id = 4)將有兩個詞‘第一’和‘員工’。如果我搜索分別爲「First」和「Employee」,然後我會得到一個更大的數據集,它不能解決我的目的。我的目標是獲得以下獨特的數據集時,我搜索「的第一名員工」

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) 

我剛纔所說的(由一幫上面的代碼好撒瑪利亞人)完美地工作,並返回上述數據集。問題是,它只適用於「第一名員工」。我在搜索時遇到了「Linq的第一步」。搜索短語在運行時傳遞給程序,可以是多少個單詞。我試圖分離Wheres,但'有'的條件未命中,哪個是整個數據集再次返回的地方。

因此,我要求你們都和藹幫助我解決這個問題。我對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

使用你自己的邏輯人! –

+1

不太清楚你需要什麼,但是你可以鏈接Where調用,比如'.Where(condition1).Where(condition2)'等等。 – vesan

+0

感謝隊友的建議。我無法破解它,因此來了專家的意見! – DevNovice

回答

2

幾個問題與您的代碼:

  1. 你之前選擇的ID 你」經過濾。這意味着您最終收集的是int s,這意味着您不能通過另一列進行過濾。你應該過濾然後選擇所需的列

  2. 你不需要最後的檢查,看看列l_id。我們已經檢查了l_id == id,如此明顯的列中存在

  3. 你現在查詢是不正確。如果任何行中的數據集相匹配您傳回行:

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(); 
} 
+0

羅布。感謝您的答覆。我想我不清楚我想要什麼。我在OP上添加了一個編輯。請你可以看一下嗎?謝謝 事情是我失去了結果集,如果我不使用&&在這種情況下至關重要 – DevNovice

+0

你可以合併兩個在一起?說'.Where(dr => dr.id> 1 && dr => dr.Field (「l_id」)== id)'。 – Bigeyes

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()中的一系列&&條目相同。

+0

David - 。感謝您的答覆。我想我不清楚我想要什麼。我在OP上添加了一個編輯。請你可以看一下嗎?謝謝 事情是我失去了結果集,如果我不使用&&在這種情況下至關重要 – DevNovice

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(); 
+0

感謝您的迴應。我很感激。讓我儘快回覆。 p.s.我編輯了一個爲我工作的解決方案的OP。但是,我會嘗試你的,並回來。再次感謝! – DevNovice