如何在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
相关产品推荐
相关产品推荐

