分享
 
 
 

用C#和数据库实现无限级分法

王朝c#·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在做软件是,碰上这个问题,要把一个商店的分类用树形来表示。

商品分类应该是无限子类划分的,怎样设计好一些。用数据库还是用XML。

由于以前搞设计,编程方面较生了,.NET也则开始学,觉得还是用数据库比较熟悉些。由于以前没这方面经验,所以对数据库设计感到比较辣手。

想了很多,比如链表,用一个Parent(父关系)、Child(子链接),后来舍弃了Child,就用Parent,只认父亲,于是设计数据库格式如下:

表名:Sort

字段:SortID(主键,自增长)、ParentID(父类ID号)、SortName(名称)、IsEnd(是否为最终类,因设计时考虑最终类下不能再分,最终类下只能具体商品。相反不是最终类下,只能再设类别,而不能下设具体商品)

数据库建好了,这是最简结构。现在说明一下库的使用方法。

Sort表最重要的字段就是ParentID,用于链接分类的关系。比如家族,你只要认准你父亲,而不必认爷爷,爷爷是父亲认的,即你-->父亲-->爷爷。只经认准各自的父亲(parent),这条链就链在一起了。再进一步,爷爷可以有兄弟,但这不是你考虑的,只要认得祖宗,而不必顾及傍支(即爷爷兄弟下的后代),傍支是别人考虑的事。

再说到数据库了,最顶级的类,ParentID = 0,说明没有父类;

如果一个类,它的父类是2号,则ParentID = 2;

万里长征,这才开始,要想使用它有很多问题。

比如树形搜索、删除节点,得到每个结点信息等。

以下是我用C#写的,用TreeView来表示分类树形

要定清楚,真是头大了,我不善写教程,只是提供一个思考方法。各位有好的思考方法也拿上来共享。

用树形来表示,化了我非常大精力,树形不好控制(刚用.Net不好意思),比如你点击一个子节点(node),要显示该节点的信息(包括名称或其它信息)。

要说明这个TreeView显示树形,先要知道一下TreeView添加节点方法。

TreeView字节点对象为TreeNode,可以用以下方法建立

TreeNode tn = new TreeNode("CustomerName");

在TreeView中添加节点

TreeView1.Nodes[1].Nodes[2].Add(tn);

如果想在tn节点上再加字节点

TreeNode tn2 = new TreeNode("Name2");

tn.Add(tn2);

以上只可建立固定的树,动态数的文字、及树的多少都是不确定的,如果都是tn1,tn2.....要定到什么时候去。所以考虑用数组存放这些Node的集合

ArrayList arrNode = new ArrayList();

一个简单的添加树的函数(是个思路,其实到现在还不完全)

nodeIndex:父节点在数组中的位置;

NodeName:Node的名称;

public void AddNode(int nodeIndex, string NodeName)

{

TreeNode tn = new TreeNode(NodeName);

((TreeNode)arrNode[nodeIndex]).Add(tn);

// 把新的Node添加到数组中去

arrNode.Add(tn);

}

嘿嘿,这是个不成器的函数,看似实现了,其实还没有。

因为从数据库中读出的了不会告知你应该在数组的那条下增加节点。从数据库中读出来的只有自身ID号及 ParentID。这要怎么实现,确实伤脑,因为数组中看不到任何关于ID及ParentID信息。

这个函数还要大大修改,在什么地方可以使每个Node具有ID及ParentID属性。我终于想办法编写自己的TreeNode组件了。

接下来,就得为TreeNode做些扩充。

新建组件,定义一个TreeNode的派生类:

public class ExNode : System.Windows.Forms.TreeNode

然后定义一个结构:

public struct Sort

{

public int ID;

public string Name;

public int ParentID;

public bool IsEnd;

public bool Disable;

}

该结构和数据库中相吻合。

该类的代码较简单,如下:

using System;

using System.Collections;

using System.ComponentModel;

using System.Drawing;

using System.Data;

using System.Windows.Forms;

namespace CrystalBiz

{

public struct Sort

{

public int ID;

public string Name;

public int ParentID;

public bool IsEnd;

public bool Disable;

}

/// <summary>

/// ExNode 的扩展

/// </summary>

public class ExNode : System.Windows.Forms.TreeNode

{

private Sort mySort;

public Sort Sort

{

get

{

return mySort;

}

set

{

mySort = value;

this.Text = mySort.Name;

}

}

public ExNode()

{

mySort = new Sort();

}

}

}

定义好的的类,就只要把原来的TreeNode换成ExNode就行了。

这个AddNode函数现在可以改了。

/// <summary>

/// 在treeView中增加Node,并把Node加入到数组,方便查询

/// </summary>

private void AddNode(Sort st)

{

ExNode pNode = new ExNode(); //要挂接的父结点

ExNode addNode = new ExNode(); //本结点

addNode.Sort = st;

// 添加到TreeView和数组

arrNode.Add(nd);

if (nd.Sort.ParentID == 0)

{

// 最上级分类,在根节点添加

trvSort.Nodes[0].Nodes.Add(addNode);

}

else

{

// 在根目录中搜索父类,如果ParentID号与数组的ID相合,则找到

foreach (ExNode node in arrNode)

{

if (node.Sort.ID == st.ParentID)

{

pNode = node;

break;

}

}

// 在找到的父节点下添加新节点

pNode.Nodes.Add(addNode);

}

}

最后一步了,胜利在望

/// <summary>

/// 重设商品分类的 TreeView

/// ResetSortView() 函数

/// </summary>

#region ResetSortView()函数实现

private void ResetSortView()

{

trvSort.Nodes.Clear();

arrNode.Clear();

ExNode nd = new ExNode();

//

// 添加商品总类

//

Sort mySort = new Sort();

mySort.ID = 0;

mySort.Name = "商品总类";

mySort.ParentID = -1;

mySort.IsEnd =false;

mySort.Disable = false;

nd.Sort = mySort;

nd.ImageIndex = 0;

nd.SelectedImageIndex = 0;

trvSort.Nodes.Add(nd);

arrNode.Add(nd);

// 打开数据库

// 不好意思,我把数据库打开都定义类了,全包装在DBClass内

// 这样换成SQL SERVER就省力些

// DataSet这里也封装,为myDB.DBDataSet

// 懒得定数据库了,如果不熟悉数据库,快学习一下

string sql = "Select * From MerchandiseSort Order by MerchandiseSortID";

DBClass myDB = new DBClass();

myDB.DBOpen();

myDB.CreateAdapter(sql);

myDB.FillDataSet();

//

// 把数据记录逐一添加到树开上去

//

for (int i = 1; i <= myDB.DBDataSet.Tables[0].Rows.Count; i++)

{

mySort.ID = (int)myDB.DBDataSet.Tables[0].Rows[i-1]["MerchandiseSortID"];

mySort.Name = myDB.DBDataSet.Tables[0].Rows[i-1]["Name"].ToString();

mySort.ParentID = (int)myDB.DBDataSet.Tables[0].Rows[i-1]["ParentID"];

mySort.IsEnd = (bool)myDB.DBDataSet.Tables[0].Rows[i-1]["IsEnd"];

mySort.Disable = (bool)myDB.DBDataSet.Tables[0].Rows[i-1]["Disable"];

AddNode(mySort);

}

myDB.DBClose();

trvSort.ExpandAll();

}

结束语

这代码肯定有问题,比如最后的,可用DataReader的可能效率更高,但我是边学边做,来不及考虑这些,而且其它事也很多,事情总要分轻重,解决大的,再追求性能。

我较喜欢艺术,以前这种追求完美的思想,在这里没发挥。否则,为了一段代码苦思冥相,结果可能什么也做不了。设计程序整体思想最要紧,整体好了,内部稍差,也不失为优秀工程,因为内部分块都可以不断改进的。

另外我在网上看了些文章,有关于XML,还没来得及仔细研究。如果有兴趣,大家讨论一下。有朋友建议搜索用递归,但我这里用了数组,不知那个更好。另外一些添加子类的方法还没写,可能比较简单些。较复杂的是删除子节点,如删除(中止)节点,则其下的子节点要全部删除,这就要搜索全部的子树了。这方面我是弱项,所以用了个折中的办法,即如果还有子类的话,就不能删除,正象DOS的删除目录法。这个我肯定以后要化时间再加强的,但不是现在。

我这人就这样,不会写最好的程序,只会写更好的程序。所以也不求程序最高效率。如果想一起讨论这个思路的话来找我好了,但如果要找完美的东西,别来找我。

补充:

为了更好实现查找及分类索,引进了IDPath(ID路径的概念)

我找到了一种使用ID路径简单的方法,不用在数据库中设置IDPath字段,只在ExNode再修改一个,增加一个私有变量:

private string mIDPath; // 分类的ID组成的路径

public string IDPath

{

get

{

return mIDPath;

}

set

{

mIDPath = value;

}

}

并在添加Node时设置:

// 添加到TreeView和数组

arrNode.Add(nd);

if (nd.Sort.ParentID == 0)

{

trvSort.Nodes[0].Nodes.Add(nd);

nd.IDPath = "root\\0";

}

else

{

foreach (ExNode node in arrNode)

{

if (node.Sort.ID == st.ParentID)

{

pNode = node;

break;

}

}

pNode.Nodes.Add(addNode);

addNode.IDPath = pNode.IDPath + "\\" + nd.Sort.ParentID.ToString();

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有