You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用SqlDataReader读取SQL Server数据填充主从列表的优化方法咨询

C# 嵌套主从对象填充的优化方案

一、原生ADO.NET优化方案(无第三方依赖)

你原有的实现逻辑是可行的,仅需调整部分细节就可以大幅提升可读性和鲁棒性:

  • 修正原代码拼写问题:你定义的Master类属性为List<Detail> Details,原逻辑中写的h.Detail属于拼写错误,容易触发空引用异常
  • 用字典缓存已创建的Master对象,无需依赖查询结果按Master ID排序,逻辑更清晰:
List<Master> result = new List<Master>();
Dictionary<int, Master> masterCache = new Dictionary<int, Master>();
// 避免SELECT *,明确指定字段减少无效数据传输
string sqlCommand = "SELECT m.ID, m.Name, d.Description, d.Amount FROM Master m LEFT JOIN Detail d on m.ID = d.ID";

using (var dr = db.DbDataReader as System.Data.SqlClient.SqlDataReader)
{
    while (dr.Read())
    {
        int masterId = dr.GetInt32("ID");
        // 缓存中不存在则创建Master对象
        if (!masterCache.TryGetValue(masterId, out var currentMaster))
        {
            currentMaster = new Master
            {
                ID = masterId,
                Name = dr.GetString("Name"),
                Details = new List<Detail>() // 提前初始化避免后续空值判断
            };
            masterCache.Add(masterId, currentMaster);
            result.Add(currentMaster);
        }
        // 跳过左连接产生的空Detail记录
        if (!dr.IsDBNull("Description"))
        {
            currentMaster.Details.Add(new Detail
            {
                Description = dr.GetString("Description"),
                Amount = dr.GetDouble("Amount")
            });
        }
    }
}

二、微型ORM方案(推荐,大幅减少样板代码)

使用Dapper这类轻量ORM,无需手动处理DataReader的字段映射、类型转换,性能和原生ADO.NET几乎无差异:

// 先安装Dapper的NuGet包
using Dapper;
using System.Data.SqlClient;

string sqlCommand = "SELECT m.ID, m.Name, d.ID, d.Description, d.Amount FROM Master m LEFT JOIN Detail d on m.ID = d.ID";
using (var conn = new SqlConnection("你的数据库连接字符串"))
{
    var masterDict = new Dictionary<int, Master>();
    var result = conn.Query<Master, Detail, Master>(sqlCommand, 
        (master, detail) => 
        {
            if (!masterDict.TryGetValue(master.ID, out var existingMaster))
            {
                existingMaster = master;
                existingMaster.Details = new List<Detail>();
                masterDict.Add(existingMaster.ID, existingMaster);
            }
            if (detail != null)
            {
                existingMaster.Details.Add(detail);
            }
            return existingMaster;
        }, splitOn: "ID") // 指定两个对象的拆分字段,第二个ID对应Detail表的主键
        .Distinct()
        .ToList();
}

三、额外优化建议

  • 补全Detail类的属性类型定义,原代码中Description和Amount未指定类型会触发编译错误,建议修改为public string Description { get; set; }和public double Amount { get; set; }
  • 若数据量较大,可改为两次查询:先查询所有Master记录,再查询所有关联的Detail记录,最后在内存中做关联,避免左连接导致的Master字段重复传输,数据量越大优化效果越明显

内容的提问来源于stack exchange,提问作者Blishton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 04:45:03