C#将两张结构相同异名表的数据合并存入同一对象的优雅方案
可行的C#端实现方案
以下是两种常用的优雅实现方式,均不需要在SQL侧拼接UNION:
方案1:轻量ORM实现(推荐,以Dapper为例)
这种方式代码量最少,维护成本最低,只需要提前把字段列表统一抽出来,分别查询两张表后合并结果集即可:
// 统一抽离查询字段,避免重复编写、减少字段不匹配的BUG var selectFields = "ID, mercid, mercname, termid, PAN, edcbatch, transeq, tranauth, trandt, trantm, trandbcr, tranamt"; var formalTable = applicationSettings.TablePOSSettlementRecords; var investigateTable = applicationSettings.TablePOSSettlementRecords_investigations; List<RegionalReportRecord> result = new List<RegionalReportRecord>(); using (var conn = new SqlConnection("你的数据库连接字符串")) { // 分别查询两张表,自动映射到实体类 var formalData = conn.Query<RegionalReportRecord>($"SELECT {selectFields} FROM {formalTable}").ToList(); var investigateData = conn.Query<RegionalReportRecord>($"SELECT {selectFields} FROM {investigateTable}").ToList(); // 合并结果:等效UNION ALL(不去重,性能更高) result.AddRange(formalData); result.AddRange(investigateData); // 如果需要和原SQL UNION逻辑一致(自动去重),替换成以下代码即可,前提是实体类已经重写Equals和GetHashCode方法 // result = formalData.Union(investigateData).ToList(); }
方案2:原生ADO.NET实现(无需引入第三方ORM)
如果项目不能引入Dapper等外部依赖,可以自己封装统一的映射方法实现:
- 先编写通用的DataReader转实体类的映射方法:
private RegionalReportRecord MapToEntity(IDataReader reader) { return new RegionalReportRecord { ID = reader.GetInt32(reader.GetOrdinal("ID")), MercId = reader.IsDBNull("mercid") ? null : reader.GetString(reader.GetOrdinal("mercid")), MercName = reader.IsDBNull("mercname") ? null : reader.GetString(reader.GetOrdinal("mercname")), TermId = reader.IsDBNull("termid") ? null : reader.GetString(reader.GetOrdinal("termid")), PAN = reader.IsDBNull("PAN") ? null : reader.GetString(reader.GetOrdinal("PAN")), EdcBatch = reader.IsDBNull("edcbatch") ? null : reader.GetString(reader.GetOrdinal("edcbatch")), TranSeq = reader.IsDBNull("transeq") ? null : reader.GetString(reader.GetOrdinal("transeq")), TranAuth = reader.IsDBNull("tranauth") ? null : reader.GetString(reader.GetOrdinal("tranauth")), TranDt = reader.IsDBNull("trandt") ? DateTime.MinValue : reader.GetDateTime(reader.GetOrdinal("trandt")), TranTm = reader.IsDBNull("trantm") ? null : reader.GetString(reader.GetOrdinal("trantm")), TranDbCr = reader.IsDBNull("trandbcr") ? null : reader.GetString(reader.GetOrdinal("trandbcr")), TranAmt = reader.IsDBNull("tranamt") ? 0 : reader.GetDecimal(reader.GetOrdinal("tranamt")) }; }
- 分别查询两张表合并结果:
var selectFields = "ID, mercid, mercname, termid, PAN, edcbatch, transeq, tranauth, trandt, trantm, trandbcr, tranamt"; var formalTable = applicationSettings.TablePOSSettlementRecords; var investigateTable = applicationSettings.TablePOSSettlementRecords_investigations; List<RegionalReportRecord> result = new List<RegionalReportRecord>(); using (var conn = new SqlConnection("你的数据库连接字符串")) { conn.Open(); // 查询正式表 using (var cmd = new SqlCommand($"SELECT {selectFields} FROM {formalTable}", conn)) using (var reader = cmd.ExecuteReader()) { while(reader.Read()) result.Add(MapToEntity(reader)); } // 查询核查表 using (var cmd = new SqlCommand($"SELECT {selectFields} FROM {investigateTable}", conn)) using (var reader = cmd.ExecuteReader()) { while(reader.Read()) result.Add(MapToEntity(reader)); } }
注意事项
- 你原来的SQL存在语法错误:第一张表查询返回12个字段,第二张表只返回10个字段,直接执行UNION会触发数据库字段数量不匹配的报错,以上两种方案统一了字段列表,可以避免该问题
- 如果你的业务数据量超过10万条,更推荐使用SQL侧UNION方案,数据库的合并运算性能远高于C#端内存合并,同时减少两次查询带来的IO开销
内容的提问来源于stack exchange,提问作者Adil15
相关产品推荐
相关产品推荐

