如何用ODP.NET Core将Oracle查询结果转为List、DataSet或JSON?
解决方案
无限循环原因说明
reader.OfType<object>()触发无限循环,是因为DbDataReader的枚举器逻辑问题:它的GetEnumerator()默认遍历行,但OfType<object>()会错误地重复读取行,导致无法终止遍历。OracleDataAdapter.Fill(data)的“无限循环”大概率是调试器假死:当查询结果集过大时,调试器展开DataSet会递归加载关联对象,造成类似无限循环的卡顿,并非代码本身存在循环。可以通过添加rownum <= 10限制查询行数验证。
最优转换方式
1. 转动态对象列表(无需实体类,灵活高效)
手动遍历Reader,用ExpandoObject生成动态对象,无需提前定义实体类:
var result = new List<object>(); using (var connection = new OracleConnection(CONNECTION_STRING)) { connection.Open(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = "select * from <table>"; using (var reader = cmd.ExecuteReader()) { // 获取所有列名 var columnNames = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName) .ToList(); while (reader.Read()) { var row = new ExpandoObject() as IDictionary<string, object>; foreach (var col in columnNames) { // 处理DBNull值,转为null row[col] = reader[col] == DBNull.Value ? null : reader[col]; } result.Add(row); } } } } return result;
这种方式兼顾灵活性和可读性,遍历一次即可完成转换,适合快速开发场景。
2. 转DataSet/DataTable(传统ADO.NET兼容方案)
如果需要兼容传统DataSet场景,优化资源管理代码即可:
using (var connection = new OracleConnection(CONNECTION_STRING)) { var dataSet = new DataSet(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = "select * from <table>"; // OracleDataAdapter会自动管理连接的打开/关闭,无需手动Open using (var adapter = new OracleDataAdapter(cmd)) { adapter.Fill(dataSet); } } return dataSet; }
注意用using块自动释放连接和资源,无需手动调用Close()——using结束时会自动执行Dispose(),包含连接关闭逻辑。
3. 直接转JSON(API场景最优)
如果最终输出是JSON,可直接从Reader转成JSON,无需中间集合:
using (var connection = new OracleConnection(CONNECTION_STRING)) { connection.Open(); using (var cmd = connection.CreateCommand()) { cmd.CommandText = "select * from <table>"; using (var reader = cmd.ExecuteReader()) { var columnNames = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName) .ToList(); var rows = new List<Dictionary<string, object>>(); while (reader.Read()) { // 每行转成字典 var rowDict = columnNames.ToDictionary( col => col, col => reader[col] == DBNull.Value ? null : reader[col] ); rows.Add(rowDict); } // 用System.Text.Json序列化 return System.Text.Json.JsonSerializer.Serialize(rows); } } }
这种方式一步到位,适合API接口直接返回JSON结果的场景。
总结
- 快速开发优先选动态对象列表:无需实体类,灵活易用。
- 传统场景选DataSet/DataTable:兼容现有ADO.NET代码,资源管理更安全。
- API输出选直接转JSON:减少中间步骤,提升效率。
内容的提问来源于stack exchange,提问作者Aymane EL Jahrani
相关产品推荐
相关产品推荐

