2011-08-19 98 views
0
 DataTable dt1 = new DataTable(); 
     DataTable dt2 = new DataTable(); 

     dt1.Columns.Add("id"); 
     dt2.Columns.Add("id"); 

     dt1.Columns.Add("val1"); 
     dt2.Columns.Add("val1"); 

     dt1.Columns.Add("val2"); 
     dt1.Columns.Add("val2"); 


     dt1.Rows.Add(new string[] { "1", "a", "a1" }); 
     dt1.Rows.Add(new string[] { "2", "b", "b1" }); 
     dt1.Rows.Add(new string[] { "", "b", "b1" }); 
     dt1.Rows.Add(new string[] { "4", "", "c1" }); 


     dt2.Rows.Add(new string[] { "1", "a", "a1" }); 
     dt2.Rows.Add(new string[] { "2", "b", "b1" }); 
     dt2.Rows.Add(new string[] { "3", "c", "c1" }); 
     dt2.Rows.Add(new string[] { "3", "c", "c1" }); 
     dt2.Rows.Add(new string[] { "4", "d", "d1" }); 
     dt2.Rows.Add(new string[] { "5", "e", "e1" }); 

結果應該只包含dt1中不存在的值。我們能做到這一點使用LINQ比較兩個DataTable多字段

+1

您是否必須使用DataTable開始? –

回答

1

是的,你可以用LINQ做到這一點,我應該這樣做:

var dataRows1 = st1.AsEnumerable().Select(r => new { 
    Id = r["id"], Val1 = r["val1"], Val2 = r["val2"] }); 

var dataRows2 = st2.AsEnumerable().Select(r => new { 
    Id = r["id"], Val1 = r["val1"], Val2 = r["val2"] }); 

這給你匿名類型,可以對被比較的IEnumerable<T>。然後,你可以這樣做:

var dt2NotInDt1 = dataRows2.Where(r2 => !dataRows1.Any(r1 => r1.Equals(r2)); 

注意,這個假設你的比較標準是在行(id含)的所有值。

還要注意調用Equals。匿名類型覆蓋Equals方法,以提供跨匿名類型的所有屬性的值比較。從"Anonymous Types" section of the C# Programming Guide

因爲匿名類型EqualsGetHashCode方法 中的 性質的EqualsGetHashcode方法來定義,同一匿名類型的兩個實例都是平等的只有 所有的屬性是平等的。

您可以根據約束條件是什麼簡化了這一邏輯。例如,如果存在主鍵(或某種唯一的行標識符),則可以將行放在鍵入該值的字典中,然後根據該字典執行查找。

在你的情況下,假設id是獨一無二的,你可以這樣做(在頂部的前兩行之後):

var dataRows1Map = dataRows1.ToDictionary(r => r.Id); 

這將會給你一張地圖,然後你就可以做一個查找(我正在切換到查詢語法,因爲我相信它在這裏更具可讀性)。

var dt2NotInDt1 = 
    for r2 in dataRows2 
    let r1Exists = dataRows1Map.ContainsKey(r2.Id) 
    let r1 = r1Exists ? dataRows1Map[r2.Id] : null 
    where 
     // Rows that don't have a primary key in the first set. 
     !r1Exists || 
     // Rows that are different. 
     !r1.Equals(r2) 
    select r2;