2011-08-19 76 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;