从与LINQ连接的两个DataTable创建组合的DataTable。 C#

我有以下代码用两个简单的SQL查询填充dataTable1dataTable2dataTableSqlJoined从相同的表填充但连接在一起。

我正在尝试编写一个可以创建dataTableLinqJoined的LINQ查询,就好像它是使用SQL创建的一样。 在下面的示例中,它仅返回dataTable1中的值。

我遇到的问题是在linq查询的SELECT中放入什么。 如何创建包含DataRows中所有列的新DataRow。 在运行时之前,我不会知道查询的确切列名/模式。

 sqlCommand = new SqlCommand("SELECT ID, A, B FROM Table1", sqlConnection, sqlTransaction); sqlAdapter = new SqlDataAdapter(sqlCommand); DataTable dataTable1 = new DataTable(); sqlAdapter.Fill(dataTable1); sqlCommand = new SqlCommand("SELECT ID, C, D FROM Table2", sqlConnection, sqlTransaction); sqlAdapter = new SqlDataAdapter(sqlCommand); DataTable dataTable2 = new DataTable(); sqlAdapter.Fill(dataTable2); sqlCommand = new SqlCommand("SELECT Table1.ID, A, B, Table2.ID, C, D FROM Table1 INNER JOIN Table2 ON Table1.ID = Table2.ID", sqlConnection, sqlTransaction); sqlAdapter = new SqlDataAdapter(sqlCommand); DataTable dataTableSqlJoined = new DataTable(); sqlAdapter.Fill(dataTableSqlJoined); var dataRows = from dataRows1 in dataTable1.AsEnumerable() join dataRows2 in dataTable2.AsEnumerable() on dataRows1.Field("ID") equals dataRows2.Field("ID") select dataRows1; // + dataRows2; DataTable dataTableLinqJoined = dataRows.CopyToDataTable(); 

对于更多背景,组合查询是非常数据库密集的并且导致性能问题。 第一个查询返回的数据相当静态,可以大量缓存。 第二个查询返回的数据不断变化但运行速度很快,因此不需要缓存。 还有很多代码依赖于组合DataTable的传递,因此在以不同格式传递数据时没有太多可行的选项可用。

你看过这个页了吗?

HOW TO:在Visual C#.NET中实现DataSet JOIN帮助器类

如果这种方法对你来说不够LINQy,你可以将行数据分解为对象数组:

 DataTable targetTable = dataTable1.Clone(); var dt2Columns = dataTable2.Columns.OfType().Select(dc => new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); targetTable.Columns.AddRange(dt2Columns.ToArray()); var rowData = from row1 in dataTable1.AsEnumerable() join row2 in dataTable2.AsEnumerable() on row1.Field("ID") equals row2.Field("ID") select row1.ItemArray.Concat(row2.ItemArray).ToArray(); foreach (object[] values in rowData) targetTable.Rows.Add(values); 

我认为这就像你能够做到的那样简洁,我会解释原因:它是架构。

DataRow不是一个独立的对象; 它取决于它拥有的DataTable ,没有它就无法生存。 没有支持的方法来创建“断开连接”的DataRow ; CopyToDataTable()扩展方法适用于已存在于一个DataTable行,只需从源复制模式(请记住,每个DataRow都有对其父Table的引用),然后再复制行本身(最有可能使用ImportRow ,尽管我没有实际上打开了Reflector来检查)。

在这种情况下,您需要创建一个新架构。 在创建任何(新)行之前,您需要先创建表来保存它们,这意味着在上面的方法顶部至少编写3行代码。

然后,您最终可以创建行 – 但一次只能创建一行,因为DataTable及其关联的DataRowCollection不会公开任何方法来一次添加多行。 当然,您可以为DataRowCollection添加自己的扩展方法,以使这种“外观”更好:

 public static void AddRange(this DataRowCollection rc, IEnumerable tuples) { foreach (object[] data in tuples) rc.Add(tuples); } 

然后你可以在第一种方法中摆脱foreach并将其替换为:

 targetTable.Rows.AddRange(rowData); 

虽然这只是在改变冗长,而不是消除它。

最重要的是,只要你使用传统的DataSet类层次结构,总会有一点点瑕疵。 Linq to DataSet扩展很好,但它们只是扩展,不能改变上面的限制。

Aaronaught很棒。 但是想为LINQy代码添加一些增强function。 在将dataTable2中的列添加到Target表时,Target表中可能已经存在很少的列(我们正在加入)。 所以我们走了。

 DataTable targetTable = dataTable1.Clone(); var dt2Columns = dataTable2.Columns.OfType().Select(dc => new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping)); var dt2FinalColumns=from dc in dt2Columns.AsEnumerable() where targetTable.Columns.Contains(dc.ColumnName) == false select dc; targetTable.Columns.AddRange(dt2FinalColumns.ToArray()); var rowData =from row1 in dataTable1.AsEnumerable() join row2 in dataTable2.AsEnumerable() on row1.Field("ID") equals row2.Field("ID") select row1.ItemArray.Concat(row2.ItemArray.Where(r2=> row1.ItemArray.Contains(r2)==false)).ToArray(); foreach (object[] values in rowData) targetTable.Rows.Add(values); 

希望这对像我这样的人有用。

如果我听起来像个白痴,请原谅我。

我想,你应该准备好决赛桌(包括表A和表B的所有字段)。
并且,不是使用LINQ,而是进行连接,然后对结果执行ForEach并将值插入到最终数据表中。

伪代码

dt1.Join(dt2).Where(…)。ForEach(row =>代码读取匿名对象的内容并将其添加到finalTable.Rows)

 select new { ID = dataRows1.ID, // no need to select dataRows2.ID, because of JOIN. A = dataRows1.A, B = dataRows1.B, C = dataRows2.C, D = dataRows2.D };