怎样从数据库中读取数据生成树

时间:2021-05-13 12:38:34
数据库
表名
Leaf
字段
id 类型为int 表示树中的节点的id值 
pareid 类型为int 表示树中的节点的父级节的id值
name 类型string 表示节点的标签  
树形节点的id值将通过以下方法取得,根节点的父级节点的id值均会被设置成“-1”。

/// <summary>
/// 获取ID号
/// </summary>
/// <returns>ID号</returns>
private int GetNum()
{
int x=0;
bool t=false;
Yds.YdsTree.PublicTree.numList.Sort();//将id进行排序(从小到大)
if(Yds.YdsTree.PublicTree.numList.Count ==0) return 0;//如果此集合为空,则返回id =0
do
{
foreach(int a in Yds.YdsTree.PublicTree.numList) //遍历此集合
{
if(x!=a) //如果id此处不连续,则中断跳出、
{
t=true;
break;
}
x=x+1;
}
if(t) break;
}
while(x<int.MaxValue);
return x;//返回找到的id值
}


以下仅为从数据库中读取数据来生成树的主要代码

namespace Yds
{
namespace YdsTree
{
public class PublicTree
{
public PublicTree()
{
}
            public static ArrayList numList = new ArrayList();//所有节点键值集合
public static  OleDbConnection Conn;//数据库连接
}

/// <summary>
        /// 定制自定义树形节点
/// </summary>
public class LeafNode:TreeNode

public readonly int Id;//键值
public int PareId;//父级健值
public LeafNode(int id ,int pareid,string name)
{
this.Id =id;
this.PareId =pareid;
this.Text  =name;
}
public override string ToString()
{
return this.Text   ;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
public override bool Equals(object obj)
{
LeafNode temobj=obj as Yds.YdsTree.LeafNode ;
if(temobj==null) return false;
if(temobj.Id  ==this.Id  )
return true;
return false;
}
}

/// <summary>
/// 自定义树,实现添加指定类型的节点和一些指定的动作与数据库关联一起
/// </summary>.
public class TreeP:TreeView
{
private Yds.YdsTree.LeafNode Xtemnode;
public TreeP()
{
}
/// <summary>
/// 对数据连接赋值的同时从数据库中读取节点,初始化树
/// </summary>
public OleDbConnection ChangeDataConn
{
get
{
return Yds.YdsTree.PublicTree.Conn  ;
}
set
{
if(value==null) return;
try
{
Yds.YdsTree.PublicTree.Conn =value;
Yds.YdsTree.PublicTree.Conn.Open();
}
catch
{
System.Windows.Forms.MessageBox.Show("数据连接未成功!");
return;
}
                    //树形节点初始化(清空);
this.Nodes.Clear();
Yds.YdsTree.PublicTree.numList.Clear();
try
{
                        string sql = "SELECT * FROM Leaf ";
OleDbCommand cmd=new OleDbCommand(sql,Yds.YdsTree.PublicTree.Conn);
OleDbDataReader rd=cmd.ExecuteReader();
Yds.YdsTree.LeafNode temleaf;
while(rd.Read())
{
temleaf=new LeafNode(System.Convert.ToInt32(rd["id"].ToString()),System.Convert.ToInt32(rd["pareid"].ToString()),rd["name"].ToString());
this.addNode(temleaf);//将此节点添加至树中。
}
this.sortRoot();
rd.Close();
}
catch(System.Data.OleDb.OleDbException ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
Yds.YdsTree.PublicTree.Conn.Close();
}
}
private void addNode(Yds.YdsTree.LeafNode temnode)
{
this.Xtemnode =new LeafNode(-1,-1,false,"");//初始化Xtemnode
this.FindNode(temnode.PareId ,this.Nodes);//查找它的父级节点,结果将保存在Xtemnode
Yds.YdsTree.PublicTree.numList.Add(temnode.Id);//收集键值
if(this.Xtemnode.Id  ==-1) 
this.Nodes.Add(temnode);//如果没找到则将其作为根添加至树中。
else
this.Xtemnode.Nodes.Add(temnode);
}
/// <summary>
            /// 重新对根进行整理,直到所有的根节点均找到它的上级节点
/// </summary>
private void sortRoot()
{
foreach(Yds.YdsTree.LeafNode temnode in this.Nodes)
{
foreach(Yds.YdsTree.LeafNode temnodex in this.Nodes )
{
if(temnode.PareId ==temnodex.Id ) 
{
this.Nodes.Remove(temnode);
temnodex.Nodes .Add(temnode);
sortRoot();
}
}
}
}
private void  FindNode(int id,System.Windows.Forms.TreeNodeCollection temnodes)
{
foreach(Yds.YdsTree.LeafNode node in temnodes)
{
if(id ==node.Id )
{
this.Xtemnode = node;
break;
}
else
this.FindNode(id,node.Nodes);
}
}
}

}
}

主要问题是如果一个子节点先从数据库中读取添加至树中,而其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,有哪位师付能帮我改正下?代码要简短,效率越高越好!谢谢!!

17 个解决方案

#1


学院派:递归
企业派:xml

#2


国内著名ERP派:
ccode

001
001001
001001001
002
002001
002001001

这种方法你会体会到未来各类查询时的方便性,妙不可言...................

保存父ID的做法,真属于垃圾做法,虽然这的许多专家乐此不彼

当然,如果楼主需要一个无限级次的树,那不要用这种方法

不怕拍砖,没人骂我剽窃就行了



#3


脑袋大中。。。

#4


to jointan:
 前一种方法好是好,就是对于每级都要定义节点的id格式,每级数量有限制,以前用VB做过。
 现在我就是要做个无限级次的树。方法是
依次从数据库中读取数据,每读取一个数据生成一个节点,在已有的树中查找它的父级,如果找到则添加至它的下级中,如果没找到则暂时作为根添加至树中。当从数据库读取数据完毕则已建立了一个初步符合要术的树,但是此时如果有的节点其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,能帮我改正下?代码要简短,效率越高越好!谢谢!!
 

怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#5


在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到

#6


在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到
这样不行,因为每个新节点id是通过GetNum()方法获取(见前面贴过的代码),而树中的节点在实际操作过程中是不断添加或删除节点的。这样就造成有的节点的id值可能比它的父级节点的id值还大,


怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#7


该回复于2010-08-12 10:09:36被版主删除

#8


建议你改一下(添加两个方法,一个字段)

            private string GetParentID(int id)
            {
                //查找只定ID的父ID,查不到返回-1;
            }
            private string GetParentName(int Name)
            {
                //查找只定ID的父ID名称,查不到返回"";
            }
            private ArrayList m_NodeList = new ArrayList();//保存已添加结点集合

            private void  AddNode(Yds.YdsTree.LeafNode newNode)
            {
                foreach (LeafNode node in m_NodeList)
                {
                    if (node.Id == newNode.Id)//节点已被添加
                        return;
                }

                if(newNode.PareId == -1)//根节点
                {
                    this.m_NodeList.Add(newNode);
                    this.Nodes.Add(newNode);
                    return;
                }

                foreach (LeafNode node in m_NodeList)
                {
                    if (node.Id == newNode.PareId)
                    {
                        this.m_NodeList.Add(newNode);
                        node.Nodes.Add(newNode);
                        return;
                    }
                }

                LeafNode parentNode = new LeafNode(parentNode.PareId, GetParentID(newNode.PareId), GetParentName(newNode.PareId));
                AddNode(parentNode);//递归调用,逐级创建父节点
                
                this.m_NodeList.Add(newNode);
                parentNode.Nodes.Add(newNode);

            }
        }


以上代码我没数库,所以没测试

#9


引用 1 楼 zw_l_1989 的回复:
学院派:递归
企业派:xml

+1

#10


还有一种方式。对数据结构中的树进行改造,放到数据库里面。有个老外是这么做的。

#11


现已改好了,大家看看可行,还没调试。
jointan的方法也不错,我以后考虑改写的。
由于本人不是从事这个行业的,白天要上班,只要晚上抽空看一下CSDN,回贴时间不及时,请大家见谅!!

            private ArrayList m_NodeList = new ArrayList();//存储未找到父的节点集合

            private void addNode(Yds.YdsTree.LeafNode temnode)
            {
                if (temnode.PareId == -1)
                {
                    this.Nodes.Add(temnode);
                    return;
                }
                this.Xtemnode = new LeafNode(-1, -1, "");
                this.FindNode(temnode.PareId, this.Nodes););//从已组成的树形视图中查找父节点

                Yds.YdsTree.PublicTree.numList.Add(temnode.Id);
                if (this.Xtemnode.Id == -1)
                    m_NodeList.Add(nodeX);//如果没找到则将此节点存放在m_NodeList集合中。
                else
                    this.Xtemnode.Nodes.Add(temnode);//如果找到了,则将此节点加入到视图树中。
            }
//以下是将m_NodeList中的节点在视图树中找到它的父级节点并添加上
private void sortRoot(ArrayList nodeX)
{
                if (nodeX.Count == 0) return;
                foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
                {
                    this.Xtemnode=new LeafNode(-1,-1,"");
                    FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
                    if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
                    this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中,从m_NodeList移除此节点
                    m_NodeList.Remove(temnode);
                }
                sortRoot(nodeX);
}
//以下是改写的
public OleDbConnection ChangeDataConn
{
...
                        this.m_NodeList.Clear();
while(rd.Read())
{
... this.addNode(temleaf,m_NodeList);
}
this.sortRoot(m_NodeList);
rd.Close();

}
...
}


怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#13


楼上都很好

#14


比较喜欢xml

#15


8楼正解,如果树不是很大的话,我觉得楼主可以用递归,

#16


引用 14 楼 xingjibing 的回复:
比较喜欢xml

我从前也用xml,直到有一次,在读取数据过程中意外停电,xml中的数据丢失了。个人认为xml作为配置文件还是可以的,作为大量的数据存储还不是首选

怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#17


大家没有发现我下面的有个错误吗?

private void sortRoot(ArrayList nodeX)
            {
                if (nodeX.Count == 0) return;
                foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
                {
 ...
                    m_NodeList.Remove(temnode);//在集合的遍历过程中不可移除对象
                }
                sortRoot(nodeX);
            }


现已改写成

private void sortRoot(ArrayList nodeX)
{
                if (nodeX.Count == 0) return;
                ArrayList temx = new ArrayList();
                foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
                {
                    this.Xtemnode=new LeafNode(-1,-1,"");
                    FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
                    if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
                    this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中
                    temx.Add(temnode);
                }
                foreach (Yds.YdsTree.LeafNode x in temx)
                {
                    m_NodeList.Remove(x);
                }
                sortRoot(nodeX);
}


怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#1


学院派:递归
企业派:xml

#2


国内著名ERP派:
ccode

001
001001
001001001
002
002001
002001001

这种方法你会体会到未来各类查询时的方便性,妙不可言...................

保存父ID的做法,真属于垃圾做法,虽然这的许多专家乐此不彼

当然,如果楼主需要一个无限级次的树,那不要用这种方法

不怕拍砖,没人骂我剽窃就行了



#3


脑袋大中。。。

#4


to jointan:
 前一种方法好是好,就是对于每级都要定义节点的id格式,每级数量有限制,以前用VB做过。
 现在我就是要做个无限级次的树。方法是
依次从数据库中读取数据,每读取一个数据生成一个节点,在已有的树中查找它的父级,如果找到则添加至它的下级中,如果没找到则暂时作为根添加至树中。当从数据库读取数据完毕则已建立了一个初步符合要术的树,但是此时如果有的节点其父级节点是后从数据库中读取的,这样先添加至树中的子节点无法摘取下来添加至它的父节点上,只能作为根添加至树中、上面主要是sortRoot()方法不对,能帮我改正下?代码要简短,效率越高越好!谢谢!!
 

怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#5


在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到

#6


在数据库里面添加一个排序字段,比如层,orderby 下 父亲永远先得到
这样不行,因为每个新节点id是通过GetNum()方法获取(见前面贴过的代码),而树中的节点在实际操作过程中是不断添加或删除节点的。这样就造成有的节点的id值可能比它的父级节点的id值还大,


怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#7


该回复于2010-08-12 10:09:36被版主删除

#8


建议你改一下(添加两个方法,一个字段)

            private string GetParentID(int id)
            {
                //查找只定ID的父ID,查不到返回-1;
            }
            private string GetParentName(int Name)
            {
                //查找只定ID的父ID名称,查不到返回"";
            }
            private ArrayList m_NodeList = new ArrayList();//保存已添加结点集合

            private void  AddNode(Yds.YdsTree.LeafNode newNode)
            {
                foreach (LeafNode node in m_NodeList)
                {
                    if (node.Id == newNode.Id)//节点已被添加
                        return;
                }

                if(newNode.PareId == -1)//根节点
                {
                    this.m_NodeList.Add(newNode);
                    this.Nodes.Add(newNode);
                    return;
                }

                foreach (LeafNode node in m_NodeList)
                {
                    if (node.Id == newNode.PareId)
                    {
                        this.m_NodeList.Add(newNode);
                        node.Nodes.Add(newNode);
                        return;
                    }
                }

                LeafNode parentNode = new LeafNode(parentNode.PareId, GetParentID(newNode.PareId), GetParentName(newNode.PareId));
                AddNode(parentNode);//递归调用,逐级创建父节点
                
                this.m_NodeList.Add(newNode);
                parentNode.Nodes.Add(newNode);

            }
        }


以上代码我没数库,所以没测试

#9


引用 1 楼 zw_l_1989 的回复:
学院派:递归
企业派:xml

+1

#10


还有一种方式。对数据结构中的树进行改造,放到数据库里面。有个老外是这么做的。

#11


现已改好了,大家看看可行,还没调试。
jointan的方法也不错,我以后考虑改写的。
由于本人不是从事这个行业的,白天要上班,只要晚上抽空看一下CSDN,回贴时间不及时,请大家见谅!!

            private ArrayList m_NodeList = new ArrayList();//存储未找到父的节点集合

            private void addNode(Yds.YdsTree.LeafNode temnode)
            {
                if (temnode.PareId == -1)
                {
                    this.Nodes.Add(temnode);
                    return;
                }
                this.Xtemnode = new LeafNode(-1, -1, "");
                this.FindNode(temnode.PareId, this.Nodes););//从已组成的树形视图中查找父节点

                Yds.YdsTree.PublicTree.numList.Add(temnode.Id);
                if (this.Xtemnode.Id == -1)
                    m_NodeList.Add(nodeX);//如果没找到则将此节点存放在m_NodeList集合中。
                else
                    this.Xtemnode.Nodes.Add(temnode);//如果找到了,则将此节点加入到视图树中。
            }
//以下是将m_NodeList中的节点在视图树中找到它的父级节点并添加上
private void sortRoot(ArrayList nodeX)
{
                if (nodeX.Count == 0) return;
                foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
                {
                    this.Xtemnode=new LeafNode(-1,-1,"");
                    FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
                    if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
                    this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中,从m_NodeList移除此节点
                    m_NodeList.Remove(temnode);
                }
                sortRoot(nodeX);
}
//以下是改写的
public OleDbConnection ChangeDataConn
{
...
                        this.m_NodeList.Clear();
while(rd.Read())
{
... this.addNode(temleaf,m_NodeList);
}
this.sortRoot(m_NodeList);
rd.Close();

}
...
}


怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#12


#13


楼上都很好

#14


比较喜欢xml

#15


8楼正解,如果树不是很大的话,我觉得楼主可以用递归,

#16


引用 14 楼 xingjibing 的回复:
比较喜欢xml

我从前也用xml,直到有一次,在读取数据过程中意外停电,xml中的数据丢失了。个人认为xml作为配置文件还是可以的,作为大量的数据存储还不是首选

怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!

#17


大家没有发现我下面的有个错误吗?

private void sortRoot(ArrayList nodeX)
            {
                if (nodeX.Count == 0) return;
                foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
                {
 ...
                    m_NodeList.Remove(temnode);//在集合的遍历过程中不可移除对象
                }
                sortRoot(nodeX);
            }


现已改写成

private void sortRoot(ArrayList nodeX)
{
                if (nodeX.Count == 0) return;
                ArrayList temx = new ArrayList();
                foreach (Yds.YdsTree.LeafNode temnode in m_NodeList)
                {
                    this.Xtemnode=new LeafNode(-1,-1,"");
                    FindNode(temnode.PareId, this.Nodes);//从已组成的树形视图中查找父节点
                    if (this.Xtemnode.Id == -1) continue;//如果没找到跳出循环,继续下一个
                    this.Xtemnode.Nodes.Add(temnode);//如果找到了,将此节点添加到视图树中
                    temx.Add(temnode);
                }
                foreach (Yds.YdsTree.LeafNode x in temx)
                {
                    m_NodeList.Remove(x);
                }
                sortRoot(nodeX);
}


怎样从数据库中读取数据生成树我正在使用《Csdn收音机》第一时间获取最新动态!