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

如何在C#中将SQL数据存入包含子列表的类集合中?

在C#中使用SqlDataReader填充包含子列表的ObservableCollection

首先明确实体类定义,确保MySubClassData被正确初始化(避免空引用错误):

public class MyClass
{
    // 原有字段示例
    public string MyString1 { get; set; }
    public int MyInt2 { get; set; }
    
    // 新增子列表,直接初始化避免空引用
    public List<MySubClass> MySubClassData { get; set; } = new List<MySubClass>();
}

public class MySubClass
{
    public string MyString3 { get; set; }
    // 建议保留关联主数据的字段,用于匹配主实例
    public int MainId { get; set; }
}

接下来分两种常见场景实现:

场景1:一次关联查询获取主/子数据(性能更优)

通过LEFT JOIN一次性查询主表和子表的所有数据,再通过字典分组将子数据对应到主实例:

var myCollection = new ObservableCollection<MyClass>();
// 用主数据ID作为键,临时存储主实例,方便分组子数据
var mainDataMap = new Dictionary<int, MyClass>();

using (var conn = new SqlConnection("你的数据库连接字符串"))
{
    conn.Open();
    // 关联查询主表和子表,确保返回主数据ID用于匹配
    var sql = @"
        SELECT 
            m.Id AS MainId, m.MyString1, m.MyInt2,
            s.MyString3
        FROM MainTable m
        LEFT JOIN SubTable s ON m.Id = s.MainId";
    
    using (var cmd = new SqlCommand(sql, conn))
    using (var reader = cmd.ExecuteReader())
    {
        while (reader.Read())
        {
            int mainId = reader.GetInt32(reader.GetOrdinal("MainId"));
            
            // 如果当前主实例未创建,先初始化并加入字典
            if (!mainDataMap.TryGetValue(mainId, out var currentMain))
            {
                currentMain = new MyClass
                {
                    MyString1 = reader.GetString(reader.GetOrdinal("MyString1")),
                    MyInt2 = reader.GetInt32(reader.GetOrdinal("MyInt2"))
                };
                mainDataMap.Add(mainId, currentMain);
            }
            
            // 处理子数据:LEFT JOIN可能返回NULL,需先判断
            if (!reader.IsDBNull(reader.GetOrdinal("MyString3")))
            {
                currentMain.MySubClassData.Add(new MySubClass
                {
                    MyString3 = reader.GetString(reader.GetOrdinal("MyString3")),
                    MainId = mainId
                });
            }
        }
    }
    
    // 将字典中的主实例转移到ObservableCollection
    foreach (var item in mainDataMap.Values)
    {
        myCollection.Add(item);
    }
}

场景2:分两次查询(逻辑更清晰)

先查询所有主数据,再循环查询每个主数据对应的子数据:

var myCollection = new ObservableCollection<MyClass>();

using (var conn = new SqlConnection("你的数据库连接字符串"))
{
    conn.Open();
    
    // 第一步:查询所有主数据
    var mainSql = "SELECT Id, MyString1, MyInt2 FROM MainTable";
    using (var mainCmd = new SqlCommand(mainSql, conn))
    using (var mainReader = mainCmd.ExecuteReader())
    {
        while (mainReader.Read())
        {
            var mainItem = new MyClass
            {
                MyString1 = mainReader.GetString(mainReader.GetOrdinal("MyString1")),
                MyInt2 = mainReader.GetInt32(mainReader.GetOrdinal("MyInt2"))
            };
            int mainId = mainReader.GetInt32(mainReader.GetOrdinal("Id"));
            
            // 第二步:查询当前主数据对应的子数据
            using (var subCmd = new SqlCommand(
                "SELECT MyString3 FROM SubTable WHERE MainId = @MainId", 
                conn))
            {
                subCmd.Parameters.AddWithValue("@MainId", mainId);
                using (var subReader = subCmd.ExecuteReader())
                {
                    while (subReader.Read())
                    {
                        mainItem.MySubClassData.Add(new MySubClass
                        {
                            MyString3 = subReader.GetString(subReader.GetOrdinal("MyString3"))
                        });
                    }
                }
            }
            
            myCollection.Add(mainItem);
        }
    }
}

常见编译/运行错误排查

  • 空引用异常:未初始化MySubClassData,确保在MyClass中直接赋值= new List<MySubClass>()
  • 字段读取错误:读取MyString3前未判断IsDBNull,导致DBNull转字符串失败
  • 类型不匹配:使用错误的GetXXX方法读取字段(比如用GetInt32读取字符串字段)
  • 子数据匹配错误:未正确使用主数据ID关联子表,导致子数据被加到错误的主实例中

内容的提问来源于stack exchange,提问作者H. Meiser

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:43:15