【问题标题】:DataTable Union数据表联盟
【发布时间】:2012-03-09 11:14:26
【问题描述】:

请您检查以下有什么问题。

我需要这个并集,但它返回 6 条记录而不是 5 条(因为“Amir”出现了两次)

DataTable dt1 = new DataTable();
dt1.Columns.Add(new DataColumn("Name"));
dt1.Rows.Add(dt1.NewRow()["Name"] = "Imran");
dt1.Rows.Add(dt1.NewRow()["Name"] = "Amir");
dt1.Rows.Add(dt1.NewRow()["Name"] = "Asif");

DataTable dt2 = new DataTable();
dt2.Columns.Add(new DataColumn("Name"));
dt2.Rows.Add(dt2.NewRow()["Name"] = "Tandulkar");
dt2.Rows.Add(dt2.NewRow()["Name"] = "Amir");
dt2.Rows.Add(dt2.NewRow()["Name"] = "Sheqwag");

 DataTable dtUnion = dt1.AsEnumerable()
  .Union(dt2.AsEnumerable()).CopyToDataTable<DataRow>();

【问题讨论】:

    标签: c# linq datatable


    【解决方案1】:

    这里的问题是 Linq 不知道你要比较Name。相反,它对所有对象类型执行其操作,它比较两个不同实例的不同哈希值。

    您需要做的是告诉 Union 方法如何比较两个项目。您可以通过创建一个自定义的IEqualityComparer 来做到这一点,该IEqualityComparer 会按照您想要的方式比较两个数据行。

    这是一个示例实现:

    class CustomComparer : IEqualityComparer<DataRow>
    {
        #region IEqualityComparer<DataRow> Members
    
        public bool Equals(DataRow x, DataRow y)
        {
            return ((string)x["Name"]).Equals((string)y["Name"]);
        }
    
        public int GetHashCode(DataRow obj)
        {
            return ((string)obj["Name"]).GetHashCode();
        }
    
        #endregion
    }
    

    当调用Union 时,你需要传入这个比较器的一个实例:

    var comparer = new CustomComparer();
    DataTable dtUnion = dt1.AsEnumerable()
          .Union(dt2.AsEnumerable(), comparer).CopyToDataTable<DataRow>();
    

    查看这里了解更多信息:
    http://msdn.microsoft.com/en-us/library/bb358407.aspx

    忠告:
    Linq 最适合自定义数据类,DataRow 不是。最好在类上有一个实际的 Name 属性,只有这样 Linq 才能真正发光。
    如果您不需要动态模式的灵活性,您应该远离 DataTable 并实现与您所需要的完全相似的自定义类,因为 DataTable 非常臃肿且缓慢。

    【讨论】:

      【解决方案2】:

      如果您的 DataTables 的架构相同,您可以只使用现有的 DataRowComparer.Default,如下所示:

      DataTable dtUnion = dt1.AsEnumerable().Union(dt2.AsEnumerable()).Distinct(DataRowComparer.Default).CopyToDataTable<DataRow>();
      

      当您需要合并超过 2 个表时,Aggregate 函数非常方便,例如:

      // Create a table "template"
      DataTable dt = new DataTable();
      dt.Columns.Add(new DataColumn("Name"));
      
      // Create a List of DataTables and add 3 identical tables
      List<DataTable> dtList = new List<DataTable>();
      dtList.AddRange(new List<DataTable>() { dt.Clone(), dt.Clone(), dt.Clone()});
      
      // Populate the 3 clones with some data
      dtList[0].Rows.Add("Imran");
      dtList[0].Rows.Add("Amir"); 
      dtList[0].Rows.Add("Asif");
      
      dtList[1].Rows.Add("Tandulkar");
      dtList[1].Rows.Add("Amir");  
      dtList[1].Rows.Add("Sheqwag");
      
      dtList[2].Rows.Add("John");
      dtList[2].Rows.Add("Sheqwag");
      dtList[2].Rows.Add("Mike");
      
      // Union the 3 clones into a single DataTable containing only distinct rows
      DataTable dtUnion = dtList
                          .Select(d => d.Select().AsEnumerable())
                          .Aggregate((current, next) => current.Union(next))
                          .Distinct(DataRowComparer.Default)
                          .CopyToDataTable<DataRow>();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-15
        • 1970-01-01
        • 2013-08-03
        • 1970-01-01
        • 2020-10-04
        • 2013-08-24
        • 2013-03-01
        • 2021-12-28
        相关资源
        最近更新 更多