求可实现多表递归外连接的LINQ查询解决方案
实现递归递进式LINQ左外连接
问题分析
你当前的代码核心问题是:对每组左右表对独立执行左外连接,再通过SelectMany拼接所有结果,这只会堆叠各组的连接数据,而非递归地将前一次连接结果作为下一次的左表进行递进式左外连接。
解决方案
要实现递归式的左外连接,需使用累积式操作(Aggregate),从第一组连接结果开始,将其作为下一次连接的左表,依次与后续右表执行左外连接,并合并每行的列数据。
辅助方法:合并行与表结构
首先需要两个辅助方法,用于合并连接后的行数据和表结构:
// 合并左右行数据,左行保留所有列,右行添加左表没有的列 private static DataRow MergeRows(DataRow leftRow, DataRow rightRow, DataTable resultTable) { DataRow newRow = resultTable.NewRow(); // 复制左行所有列 foreach (DataColumn col in leftRow.Table.Columns) { newRow[col.ColumnName] = leftRow[col]; } // 复制右行非重复列 if (rightRow != null) { foreach (DataColumn col in rightRow.Table.Columns) { if (!resultTable.Columns.Contains(col.ColumnName)) { newRow[col.ColumnName] = rightRow[col]; } } } return newRow; } // 合并两个表的结构,用于生成结果表的Schema private static DataTable MergeSchema(DataTable leftTable, DataTable rightTable) { DataTable resultTable = leftTable.Clone(); foreach (DataColumn col in rightTable.Columns) { if (!resultTable.Columns.Contains(col.ColumnName)) { resultTable.Columns.Add(col.ColumnName, col.DataType); } } return resultTable; }
主逻辑:递归递进左外连接
使用Aggregate累积执行连接,逐步构建最终结果:
// 先验证输入列表长度匹配 if (onLeftJoinTables.Count != onRightJoinTables.Count || onLeftJoinTables.Count != columnKeys.Count) throw new ArgumentException("表列表与键列表长度必须一致"); // 初始化第一组表的连接结果 var firstLeftTable = onLeftJoinTables[0]; var firstRightTable = onRightJoinTables[0]; var firstJoinKey = columnKeys[0]; // 构建初始结果表结构 var resultSchema = MergeSchema(firstLeftTable, firstRightTable); var initialJoinResult = from leftRow in firstLeftTable.AsEnumerable() join rightRow in firstRightTable.AsEnumerable() on leftRow[firstJoinKey] equals rightRow[firstJoinKey] into joinedGroup from rightRow in joinedGroup.DefaultIfEmpty() select MergeRows(leftRow, rightRow, resultSchema); // 递归处理剩余的表对,累积执行左外连接 var finalResult = onLeftJoinTables.Skip(1) .Zip(onRightJoinTables.Skip(1), (leftTbl, rightTbl) => new { Left = leftTbl, Right = rightTbl }) .Zip(columnKeys.Skip(1), (tablePair, key) => new { tablePair.Left, tablePair.Right, JoinKey = key }) .Aggregate(initialJoinResult, (currentLeftRows, nextPair) => { // 更新结果表结构,加入右表的新列 resultSchema = MergeSchema(resultSchema, nextPair.Right); var rightRows = nextPair.Right.AsEnumerable(); var joinKey = nextPair.JoinKey; // 执行左外连接并合并行 return from leftRow in currentLeftRows join rightRow in rightRows on leftRow[joinKey] equals rightRow[joinKey] into joinedGroup from rightRow in joinedGroup.DefaultIfEmpty() select MergeRows(leftRow, rightRow, resultSchema); }) .CopyToDataTable(); // 若需提取特定列(如RS_ID),可直接从最终结果中获取 var rsIdList = finalResult.AsEnumerable().Select(row => row["RS_ID"]).ToList();
针对你的表结构说明
对于你给出的表对:
- [Applicant, Authorisation, APL_ID]
- [Authorisation, Decision, DCN_ID]
- [Authorisation, Use, USE_ID]
需确保onLeftJoinTables的后续左表是前一次连接的结果表(而非原始的Authorisation表),这样递进连接时才能基于已合并的行数据匹配键值。如果你的输入列表是原始表,可调整初始逻辑,将第一次连接的结果作为后续连接的左表。
内容的提问来源于stack exchange,提问作者rhz84
相关产品推荐
相关产品推荐

