Telerik C# RadTreeNode重复子节点问题解决咨询
问题描述
尝试获取指定路径的子节点时,成功获取但出现重复节点,推测是foreach循环次数导致该问题。以下是实现代码及界面重复节点现象截图:
实现代码
private void AgregarSubnodos(RadTreeNode parentNode, string carpetaPadre) { try { // Abrir conexión SQL string cadenaConexionSQL = Global.GeneraConexionSQL(); SqlConnection connection = new SqlConnection(cadenaConexionSQL); connection.Open(); // Obtener las subcarpetas de la carpeta padre string[] subCarpetas = Directory.GetDirectories(carpetaPadre); foreach (string subCarpeta in subCarpetas) { string cadenaSQL = "SELECT carpeta_nodo FROM SEG_NODOS WHERE carpeta_nodo LIKE '" + subCarpeta + "%'"; string mensajeVuelta = ""; SqlDataReader dataReaderNodos; dataReaderNodos = Global.EjecutaComandoReaderSQL(cadenaConexionSQL, cadenaSQL, ref mensajeVuelta); if (dataReaderNodos.HasRows) { while (dataReaderNodos.Read()) { // Get the folder name of the current data reader row string nombreCarpeta = dataReaderNodos.GetString(0); // Create a new node for the subfolder RadTreeNode subNode = new RadTreeNode(); subNode.Text = Path.GetFileName(subCarpeta); subNode.Tag = subCarpeta; // Node source subNode.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); // Add the node as a subnode of the parent node parentNode.Nodes.Add(subNode); // Recursively add subnodes for current subfolder AgregarSubnodos(subNode, subCarpeta); } } dataReaderNodos.Close(); } connection.Close(); } catch (UnauthorizedAccessException) { } catch (Exception ex) { Global.SuperLog("Error al agregar subnodos: " + ex.Message); } }
界面重复节点现象

解决方案
问题根源
代码中存在核心逻辑错误:每读取一条SQL查询结果,就创建并添加一次相同的子节点。例如当SQL查询返回3条匹配subCarpeta的记录时,会循环3次,每次都生成一个文本、Tag完全一致的节点加到父节点下,最终导致重复。
修复步骤
- 调整节点创建逻辑:将节点的创建和添加操作移到
while循环外部,每个subCarpeta只创建一次节点,无论SQL返回多少条记录。 - 修复SQL注入风险:原代码直接拼接字符串生成SQL语句,存在安全漏洞,改用参数化查询。
- 优化连接管理:使用
using语句自动管理数据库连接和资源,避免泄漏。
修复后的代码
private void AgregarSubnodos(RadTreeNode parentNode, string carpetaPadre) { try { string cadenaConexionSQL = Global.GeneraConexionSQL(); string[] subCarpetas = Directory.GetDirectories(carpetaPadre); foreach (string subCarpeta in subCarpetas) { // 使用参数化查询避免SQL注入,根据业务需求调整匹配条件(示例为精确匹配) string cadenaSQL = "SELECT carpeta_nodo FROM SEG_NODOS WHERE carpeta_nodo = @CarpetaPath"; string mensajeVuelta = ""; // 用using自动管理连接、命令、阅读器的生命周期 using (SqlConnection connection = new SqlConnection(cadenaConexionSQL)) { connection.Open(); using (SqlCommand cmd = new SqlCommand(cadenaSQL, connection)) { cmd.Parameters.AddWithValue("@CarpetaPath", subCarpeta); using (SqlDataReader dataReaderNodos = cmd.ExecuteReader()) { // 只要数据库中存在该文件夹的记录,就创建一次节点 if (dataReaderNodos.HasRows) { RadTreeNode subNode = new RadTreeNode(); subNode.Text = Path.GetFileName(subCarpeta); subNode.Tag = subCarpeta; subNode.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); parentNode.Nodes.Add(subNode); // 递归处理当前文件夹的子节点 AgregarSubnodos(subNode, subCarpeta); } } } } } } catch (UnauthorizedAccessException) { // 可添加日志记录,排查权限问题 } catch (Exception ex) { Global.SuperLog("Error al agregar subnodos: " + ex.Message); } }
额外说明
- 如果业务需要匹配当前文件夹及其所有子目录的数据库记录,保留
LIKE条件即可,但仍只需创建一次当前文件夹的节点,无需循环所有查询结果。 - 原代码中重复打开/关闭数据库连接的操作会降低性能,
using语句能自动释放资源,提升代码稳定性。
内容的提问来源于stack exchange,提问作者Hugo Jiménez
相关产品推荐
相关产品推荐

