每个目录应该包含多个子目录,但最多只有一个父目录,应该只有一种最简单、最合理选择:每个目录有唯一主键及父目录主键。
目录编号是唯一的,属于字符串(VarChar)类型,它可以被修改,不同于主键。关键一点是:某目录的编号去掉最后N位,就是父目录的编号。N取决于任一目录下最多的子目录数目,超出100个子目录的情况很少碰到,因此一般为2足够。比如下表:
主键 | 编号 | 名称 |
- | 00 | 中国 |
- | 0000 | 北京 |
- | 0001 | 山东 |
- | 000100 | 青岛 |
这种方式做相对有什么好处呢?这可以消除额外的数据库连接操作,大大提高基于目录层次的查询效率,而且非常灵活,可以自由筛选目录层级。这也是被各大门户网站所采用的频道分类的方式。目录、频道、地域、部门等所有树状结构,都可以采用这种方式保存。
当然,有利就有弊,这种方式的问题在于增删改时,编程工作量大一些,系统开销也较大。不过,性能上这不算问题,毕竟增删改操作不常发生。因为目录这样的数据需要被缓存,所以还应考虑缓存同步。下面就简单说一下不同操作的思路,其关键是就是编号字段。
一、查找子目录
子目录的编号,一定包含父目录编号,而且是从第一位开始,不管是其下面第几层子目录。如果要限制层级,比如只找一级子目录,限制子目录编号位数即可。代码上实现,如探囊取物耳。
二、查找目录下元素
比如部门下的员工,栏目下的文章等。完全不需要表连接操作,查找目录编号字段从第一位包含待查询的目录编号的所有记录即可。SQL或LINQ to SQL也同样简单。
三、添加操作
1. 首先根据其上级目录编号,找到其现有全部子目录,取每个子目录编号后两位,形成一个100内的整数集合。如果没有上级目录,则上级目录编号为Empty。
2. 根据得到的子目录识别符集合,获取一个未被使用的识别符,长为两位字符串。
3. 上级目录编号与新目录识别符拼接,连成新目录编号。
四、修改操作
改其他字段没什么问题。如果要修改上级目录,要走以下步骤:
1. 假设此目录叫X,找到X的所有层级的子目录。
2. 按照添加操作的步骤,为X生成在新的上级目录下的新目录编号。
3. 将其所有子目录的目录编号中包含的X的原编号,替换为新编号。
4. 将每个编号修改过的目录下的元素,旧编号替换为新编号。
五、删除操作
1. 查找所有目录下元素,如果集合不为空,可根据业务逻辑,将所有元素删除,或取消操作。
2. 查找所有子目录并删除。
高效目录存储结构的基本操作便是这五种。不知道我写得是不是清楚,不过无论怎么说,这种模式的美感要在实践应用中才能体会。在下文中,将描述其B/S项目中的具体应用。
在此,要向我的指导老师-刘金钢为当年的顶撞表示诚挚歉意,不管他能否看到这篇文章。