DataTable Union

时间:2012-03-09 11:14:27

标签: c# linq datatable

请你检查一下这里有什么问题。

我需要联合此但它返回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>();

2 个答案:

答案 0 :(得分:10)

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

你需要做的是告诉联盟方法如何比较两个项目。您可以通过创建自定义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>(); 时,您需要传入此比较器的实例:

DataRow

有关详细信息,请参阅此处:
http://msdn.microsoft.com/en-us/library/bb358407.aspx

建议:
Linq最适合自定义数据类,DataTable不是。最好在课堂上有一个实际的Name属性,只有Linq才能真正发光 如果您不需要动态模式的灵活性,则应远离DataTable并实现类似于您所需的自定义类,因为{{1}}非常臃肿且缓慢。

答案 1 :(得分:4)

如果您的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>();