当前位置:编程学习 > C#/ASP.NET >>

C# 树结构速度优化问题。

表结构设计如下:
TableName
ID(自增ID)  Name(节点名称)  ParentID(上级ID)

第一级为0

private DataSet createDataSet()
    {
        ds = new DataSet();
        string sqlStr = "select * from TableName ";
        SqlDataAdapter cmdSelect = new SqlDataAdapter(sqlStr, Conn);
        cmdSelect.Fill(ds, "TableName");
        return ds;
    }
    protected void InitTree(TreeNodeCollection Nds, string parentId)//用递归方法动态生成节点
    {
        DataView dv = new DataView();
        TreeNode tmpNode;
        dv.Table = ds.Tables["TableName"];
        dv.RowFilter = "parentid=" + "'" + parentId + "'";
        foreach (DataRowView drv in dv)
        {
            tmpNode = new TreeNode();
            tmpNode.Value = drv["id"].ToString();
            tmpNode.Text = drv["Name"].ToString();
            tmpNode.NavigateUrl = "StoreAdmin.aspx?RegionID="+drv["id"].ToString()+"&ParentID="+parentId;
            tmpNode.Target = "RightMenu";
            // tmpNode.SelectAction = TreeNodeSelectAction.Expand;
            Nds.Add(tmpNode);
            this.InitTree(tmpNode.ChildNodes, tmpNode.Value);
        }
    }
    protected void tvMenu_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            tvMenu.Dispose();
            Conn.Open();
            this.createDataSet();
            Conn.Close();
            this.InitTree(tvMenu.Nodes, "0");
        }
    }

-----------------------------------------------------------
这种设计方法,树结构数量大了,显得很慢,请大家帮忙,有没更好的方式实现。 --------------------编程问答-------------------- 不是数据量大的问题,而是你跑了太多个query。比方说,即使第一个select返回了1000条记录并且每个记录都没有子节点,你也要往数据库跑1001个来回,能不慢吗?

简单的解决办法是写一个SQL Stored Proc,把这个循环逻辑放在里面,然后在C#里面只要调用这个Stored Proc,一次就能返回整个要求的树结构了。

这里有一个Stored Proc读树结构的例子(level相关的部分可以省掉):
http://www.vbforums.com/showthread.php?t=366078 --------------------编程问答-------------------- 还有一种方法,就是每一级节点取一次数据,比如说默认时读取第一级节点,然后在展开某个节点时,再读取该节点的下级节点数据. --------------------编程问答-------------------- 帮顶
--------------------编程问答-------------------- treeview那样可以不? --------------------编程问答-------------------- up --------------------编程问答-------------------- 没有设计级别,数据库加个字段就会快好多了。 --------------------编程问答-------------------- 关注,帮顶.就是每一级节点取一次数据,比如说默认时读取第一级节点,然后在展开某个节点时,再读取该节点的下级节点数据.
--------------------编程问答-------------------- 分级读取数据,不要一次都加载完 --------------------编程问答-------------------- 使用节点标识,一层层来. --------------------编程问答-------------------- 最好不要用递归,效率太低了,用迭代方式,然后不要把所需的数据一次全查出来,每次只读你需要的数据,最好用多线程来实现,两个线程,一个线程读取数据库的数据,另外一个线程来处理界面的结点生成. --------------------编程问答-------------------- 最基本的方法 查询语句 select * 改掉~~用到哪个字段查哪个字段,不要 “*” --------------------编程问答-------------------- 我说下我的方法:
1.数据库的读取,还是建议一次性读取完比较好, 如果每次只读取一部分的话 后面很有可能会频繁连接数据库,这在设计上是不合理的。当然用递归读取树形的数据库效率是相当低的,你用多线程也不会很快。我曾经用的方法就是 在数据里面增加一个字段 这个字段就是路径字段 如:宇宙《银河系《太阳系《地球《中国《。。。。 这样你搜索的是就按照这个这段来搜,相当的快 如你要找地球下面的所有的:select * from tablename where path like '宇宙《银河系《太阳系《地球%'. 这里有参考
2.对于生成treeview问题 这里我建议不要一次生成完 这样数据量大的时候很容易造成界面假死的现象。我的思路是 最开始只显示节点下面的一层,当点击某个节点的时候在显示此节点的下一层。这样速度也很快,也不至于有死机的问题。
参考代码:

        #region TreeView AfterSelect Event.
        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            this.getCon();
            string name = this.treeView1.SelectedNode.Text.ToString();
            this.treeView1.SelectedNode.Nodes.Clear(); // Clear the selected node's children nodes.

            SortedList<string, int> childern = findUnder(name); // Find the child nodes from the data.

            foreach (KeyValuePair<string, int> s in childern)
            {
                if (data.Contains(s.Key)) // Check the srearch contain the nodes.
                {
                     TreeNode child = new TreeNode(s.Key.ToString());
                     this.treeView1.SelectedNode.Nodes.Add(child); // Add the found nodes into the selected node.
                     data.Remove(s.Key);
                }
            }
            for (int k = 0; k < data.Count; k++) 
            {
                TreeNode child = new TreeNode(data[k].ToString());
                this.treeView1.Nodes.Add(child);
            }
            this.treeView1.SelectedNode.Expand();
            this.showInfo(name); // Show the selected node's information.
            this.odcConnection.Close();// Close the data connection.
        }


最后附上我的联系方式, 以后有机会大家一起探讨一下
QQ:287072382
MSN:tbeck-zhang@hotmail.com --------------------编程问答--------------------     #region TreeView AfterSelect Event.
        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            this.getCon();
            string name = this.treeView1.SelectedNode.Text.ToString();
            this.treeView1.SelectedNode.Nodes.Clear(); // Clear the selected node's children nodes.

            SortedList<string, int> childern = findUnder(name); // Find the child nodes from the data.

            foreach (KeyValuePair<string, int> s in childern)
            {
                if (data.Contains(s.Key)) // Check the srearch contain the nodes.
                {
                     TreeNode child = new TreeNode(s.Key.ToString());
                     this.treeView1.SelectedNode.Nodes.Add(child); // Add the found nodes into the selected node.
                     data.Remove(s.Key);
                }
            }
            for (int k = 0; k < data.Count; k++) 
            {
                TreeNode child = new TreeNode(data[k].ToString());
                this.treeView1.Nodes.Add(child);
            }
            this.treeView1.SelectedNode.Expand();
            this.showInfo(name); // Show the selected node's information.
            this.odcConnection.Close();// Close the data connection.
        }

--------------------编程问答-------------------- 顶楼上的哈,每个节点先取数,可以快速生成树!!
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,