2015-06-23 81 views
0

我有兩個DataTablesdtChilddtMasterenter image description here在第二個數據表中找到某個列的匹配項

每行dtChild,我想看看是否有在dtMaster匹配。這個匹配是基於特定的列。

所以上面的圖片中,既有DataTables有一個名爲col2的COL3列。這些是我們感興趣的專欄。在第二行中,我們有一個匹配。因爲在dtMaster一排col2的等於對Value22Value23值和值COL3相等的。

我想寫一個LINQ查詢,將第一行結果返回null(因爲沒有匹配的dtChild第一絲束)和第二行返回找到的記錄的ID在dtMaster (讓我們假設dtMaster在這種情況下也有一個名爲Id的主鍵列)。

N.B.每次我們運行程序時,列名都可能有所不同。所以我們希望我們的LINQ是動態的。同樣,匹配列的數量(上例中爲2)可以變化。因此,可能會出現我們的情況基於5列值的情況。

+0

如果有多個匹配怎麼辦?你想只有第一場比賽的id(我認爲是Col1)嗎? –

+0

你的邏輯中有一些非常錯誤「對於dtChild中的每一行,我想看看dtMaster中是否有匹配」。主/子關係的要點是,主人的行總是存在,而孩子可能存在也可能不存在,而不是相反的 –

+0

@TimSchmelter好問題。我們只關心第一場比賽。我們希望匹配返回到名爲'Id'的列的值,與其他名稱不同。 – Disasterkid

回答

1

你可以使用:

DataTable dtResult = dtChild.Clone(); 
foreach(DataRow row in dtChild.Rows) 
{ 
    DataRow newRow = dtResult.Rows.Add(); 
    newRow.SetField("Col1", row.Field<string>("Col1")); 
    DataRow firstmatchingRow = dtMaster.AsEnumerable() 
     .FirstOrDefault(r => r.Field<string>("Col2") == row.Field<string>("Col2") 
          && r.Field<string>("Col3") == row.Field<string>("Col3")); 
    string col2 = null; 
    string col3 = null; 
    if(firstmatchingRow != null) 
    { 
     col2 = firstmatchingRow.Field<string>("Col2"); 
     col3 = firstmatchingRow.Field<string>("Col3"); 
    } 
    newRow.SetField("Col2", col2); 
    newRow.SetField("Col3", col3); 
} 

如果你想有一個動態的方法,在這裏你可以同時指定表,你可以使用這個關鍵柱:

string[] keyColumnNames = { "Col2", "Col3" }; 
DataTable dtResult = dtChild.Clone(); 

DataColumn[] childColumns = dtResult.Columns.Cast<DataColumn>() 
    .Where(c => keyColumnNames.Contains(c.ColumnName)) 
    .ToArray(); 
DataColumn[] masterColumns = dtMaster.Columns.Cast<DataColumn>() 
    .Where(c => keyColumnNames.Contains(c.ColumnName)) 
    .ToArray(); 

foreach (DataRow row in dtChild.Rows) 
{ 
    DataRow newRow = dtResult.Rows.Add(); 
    newRow.SetField("Col1", row.Field<string>("Col1")); 
    var matchingRows = dtMaster.AsEnumerable() 
     .Where(masterRow => !masterColumns.Select(mc => masterRow.Field<string>(mc)) 
      .Except(childColumns.Select(cc => row.Field<string>(cc))) 
      .Any()); 
    DataRow firstMatchingRow = matchingRows.FirstOrDefault(); 
    foreach(DataColumn col in childColumns) 
     newRow.SetField(col, firstMatchingRow == null 
      ? null 
      : firstMatchingRow.Field<string>(col.ColumnName)); 
} 
+0

每次我們運行程序時,列名都可能有所不同。所以我們希望我們的LINQ是動態的。同樣,匹配列的數量(上例中爲2)可以變化。因此,可能會出現我們的情況基於5列值的情況。 – Disasterkid

+1

@Pedram:看看。 –

+0

我要去嘗試第二種解決方案。將會回來。謝謝。 – Disasterkid

0

沒有測試...

class Data<T>() 
{ 
    public int Id {get; set;} 
    public T Value{get; set;} 
} 

var cols=dtChild.Columns.OfType<DataColumn>().All(c=>c.Name).toList(); 
var idCol=cols.Single(c=>c=="Id"); 
var valcols=cols.Where(c=>c!="Id"); 

var lst=new List<Data>(); 
var chlds=dtChild.Rows.OfType(DataRow); 
chlds.ToList().ForEach(c=>lst.Add(new Data{ Id=c[idCol], Value=null}); //initialize to null 

foreach(var r1 in chlds) 
{ 
    foreach(var r2 in dtMaster.Rows.OfType(DataRow)) 
    { 
    if (r1[idcol]==r2[idCol]) 
    { 
     forech(var c in valCols) 
     { 
     if (r1[c]==r2[c]) 
     { 
      lst.Single(l=>l.Id==r1[c]).Value= r2[idCol]; 
      break; 
     } 
     } 
    } 
    } 
} 
相關問題