2017-02-14 25 views
-1

特定の文字列のデータテーブルを検索し、特定の条件(一意のIDフィールド)に基づいてデータテーブル全体のサブセットを返すコードがあります。以下のサンプルコードでは、データテーブル内で "First"と "Employee"を検索し、同じl_id値を持つエントリだけを返します。動的に 'Linqのwhere句を作成する

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

ここで、検索テキストを動的に取得したらどうすればいいですか? 〜のために 。たとえば、上記のコードで「First」と「Employee」と「給与」を渡さなければならない場合は、どうすればよいですか?

これを一般化するにはどうすればよいですか?

ご協力いただきありがとうございます。

EDIT - 私は私のポストで明らかにされていないので、私は再び

を言い換えるてみましょう私は、この

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'です。私はユニークなフレーズ "First Employee"を検索したいと思います.1つのl_id(この場合はl_id = 4)に "First"と "Employee"の両方の単語があります。 「First」と「Employee」を別々に使用すると、私の目的を解決しない大きなデータセットが得られます。私の目標は、私が「最初の従業員」SQL用語で

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 

を検索する場合は、以下のユニークなデータセットを取得することで、これは

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) 

私はによって助けられた(言及している上記のコードに似ています良いサマリアン)完璧に動作し、私に上記のデータセットを返します。問題は「First Employee」だけで動作することです。私は「Linqの第一歩」と言って検索に困っている。検索フレーズは実行時にプログラムに渡され、いつまでの言葉がどれくらいである可能性があります。私はWheresを分離しようとしましたが、 'having'条件のミスとデータセット全体が再び返されます。

私はあなたにこの問題を私に親切に助けてください。私はLinqにとってとても新しいので、自分のやり方で働こうとしています。その間、私が得ることができるどんな助けも高く評価されるでしょう。ありがとう。

---(誰かの助けを借りて)EDITこれは、このコードを使用して作業してしまった

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(condition1).Where(condition2)'のようにWhereの呼び出しを連鎖させることができます。 – vesan

+0

アドバイスをいただき、ありがとうございます。私はそれを解読することができないので、専門家のアドバイスのために来た! – DevNovice

答えて

2

あなたのコードを持ついくつかの問題:

  1. あなたは前にID を選択しています」フィルタリングされました。つまり、intのコレクションになります。つまり、別の列でフィルタリングできません。 をフィルタリングする必要があります。必要な列を選択してください。

  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

2つの場所を一緒にマージできますか? '.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 

が、すべてのデータは、データテーブルにすでに存在する場合には、 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