6.6.4 数据库与递归搭配的技巧
这一节讨论一个非常实用的示例,将分类数据从数据库中提取出来,再通过递归技巧根据分类建立TreeView节点。
示例CatTreeVeiw
为了实现这个示例,我们设计了一个用来储存技术文件分类名称的数据库,数据表结构与其中所储存的数据如下图所示。
数据表中的每一笔数据均代表一个特定的分类项目,字段bookCatID则是这个分类的唯一识别编号,字段bookCatIDParent用来链接分类项目的上一层分类,如果当前这一个分类项目是某个分类的子分类,则此字段必须填入其上层分类项目的bookCatID。
先来看看这个示例的执行结果,页面如下图所示。
这个示例的重点在于数据表的设计,也就是关联字段bookCatIDParent,我们通过这个字段运用递归式,提取所需的架构数据。网页的内容很简单,配置了一个TreeView控件,配置程序代码的内容如下:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
String sqlString = "SELECT * FROM BooksCat ";
SqlConnection sqlConn = new SqlConnection(
System.Configuration.ConfigurationManager.
ConnectionStrings[
"CBooksConnectionString"].ToString());
SqlCommand sqlCmd = new SqlCommand(sqlString, sqlConn);
DataSet dataSet = new DataSet();
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCmd);
sqlDataAdapter.Fill(dataSet);
DataTable dt = dataSet.Tables[0];
SetTreeViewNode(dt, "0000", null);
}
}
private void SetTreeViewNode(DataTable dt ,
string parentID ,
TreeNode treeNode)
{
DataView dv = dt.DefaultView;
dv.Sort = "bookCatIDParent";
DataRowView[] drvs = dv.FindRows(parentID);
if (drvs.Length > 0)
{
foreach (DataRowView drv in drvs)
{
String bookCatIDParent = drv["bookCatID"].ToString();
String bookCatDesc = drv["bookCatDesc"].ToString();
TreeNode newTreeNode = new TreeNode( bookCatDesc +
"[" + bookCatIDParent + "]" );
SetTreeViewNode(dt, bookCatIDParent, newTreeNode);
SetTreeView(treeNode, newTreeNode);
}
}
}
private void SetTreeView(TreeNode treeNode, TreeNode newTreeNode)
{
if (treeNode == null)
BookViewTreeView.Nodes.Add(newTreeNode);
else
treeNode.ChildNodes.Add(newTreeNode);
}
}
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
String sqlString = "SELECT * FROM BooksCat ";
SqlConnection sqlConn = new SqlConnection(
System.Configuration.ConfigurationManager.
ConnectionStrings[
"CBooksConnectionString"].ToString());
SqlCommand sqlCmd = new SqlCommand(sqlString, sqlConn);
DataSet dataSet = new DataSet();
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCmd);
sqlDataAdapter.Fill(dataSet);
DataTable dt = dataSet.Tables[0];
SetTreeViewNode(dt, "0000", null);
}
}
private void SetTreeViewNode(DataTable dt ,
string parentID ,
TreeNode treeNode)
{
DataView dv = dt.DefaultView;
dv.Sort = "bookCatIDParent";
DataRowView[] drvs = dv.FindRows(parentID);
if (drvs.Length > 0)
{
foreach (DataRowView drv in drvs)
{
String bookCatIDParent = drv["bookCatID"].ToString();
String bookCatDesc = drv["bookCatDesc"].ToString();
TreeNode newTreeNode = new TreeNode( bookCatDesc +
"[" + bookCatIDParent + "]" );
SetTreeViewNode(dt, bookCatIDParent, newTreeNode);
SetTreeView(treeNode, newTreeNode);
}
}
}
private void SetTreeView(TreeNode treeNode, TreeNode newTreeNode)
{
if (treeNode == null)
BookViewTreeView.Nodes.Add(newTreeNode);
else
treeNode.ChildNodes.Add(newTreeNode);
}
}
SetTreeViewNode与SetTreeView这两个函数分别用来设置TreeView控件的组成节点,SetTreeViewNode接受3个参数:dt为整个分类数据表的数据内容;parentID用来取得所有bookCatIDParent字段等于此参数的数据;treeNode则是取得的数据所要附加上去的上层节点。其中阴影部分的程序代码调用自已形成递归运算,直至传送进去的parentID再也没有数据以其为上层分类。SetTreeView则执行节点的创建动作。
现在回到Page_Load方法,这个事件处理程序在网页加载的时候执行,其中首先取得BooksCat数据表的内容,然后引用SetTreeViewNode方法,将取得的DataTable对象及最上层分类项目的bookCatIDParent域值--0000,当做参数输入,由于是最上层的分类,因此最后一个参数直接设为null。
通过数据表字段的关联设计及递归式的运用,我们就可以在页面上轻松地呈现出一个不限层次的树状架构图,善用这个技术,可以让你设计出非常具有弹性的树状导航架构。