在度娘上查了大半个月的资料,最后发现每个网友分享的文章都有一定的错误(PS:大家是故意的么?)。最后是在看了一个ASP版本后知道了大概流程;看了一个存储过程实现的文章后知道了大概需要的功能;看了一个SQL语句看到了比较直观的实现;看了一个php示例后才知道最复杂的一个功能的实现。每篇文章都是网友们自己正在使用或已经测试通过的,但都很巧,恰好关键地方就有点出错,不过还是感谢这些资料了,不然我也搞不出来。
因为查了很久的资料,基本上没有可用的,所以一直不敢直接写到项目的DAL里面,就直接在控制器里面写方法进行了调试,暂时没考虑什么意外情况和效率问题,毕竟出现上述问题的前提条件是你这个功能要实现吧,呵呵,下面直接上代码(PS:有点丑,见谅)。
1 //数据初始化,反正失败了几十次,所以就在前面写了段初始化的代码,经常用到 2 cManager.DelByCondition(c => c.Id != 0); 3 Models.CmsMiee_Article_Category cate1 = new Models.CmsMiee_Article_Category() { Name = "商品", ClassLeftNum = 1, ClassRightNum = 18, ListSkin = "test", ContentSkin = "text" }; 4 Models.CmsMiee_Article_Category cate2 = new Models.CmsMiee_Article_Category() { Name = "食品", ClassLeftNum = 2, ClassRightNum = 11, ListSkin = "test", ContentSkin = "text" }; 5 Models.CmsMiee_Article_Category cate3 = new Models.CmsMiee_Article_Category() { Name = "肉类", ClassLeftNum = 3, ClassRightNum = 6, ListSkin = "test", ContentSkin = "text" }; 6 Models.CmsMiee_Article_Category cate4 = new Models.CmsMiee_Article_Category() { Name = "猪肉", ClassLeftNum = 4, ClassRightNum = 5, ListSkin = "test", ContentSkin = "text" }; 7 Models.CmsMiee_Article_Category cate5 = new Models.CmsMiee_Article_Category() { Name = "蔬菜类", ClassLeftNum = 7, ClassRightNum = 10, ListSkin = "test", ContentSkin = "text" }; 8 Models.CmsMiee_Article_Category cate6 = new Models.CmsMiee_Article_Category() { Name = "白菜", ClassLeftNum = 8, ClassRightNum = 9, ListSkin = "test", ContentSkin = "text" }; 9 Models.CmsMiee_Article_Category cate7 = new Models.CmsMiee_Article_Category() { Name = "电器", ClassLeftNum = 12, ClassRightNum = 17, ListSkin = "test", ContentSkin = "text" }; 10 Models.CmsMiee_Article_Category cate8 = new Models.CmsMiee_Article_Category() { Name = "电视机", ClassLeftNum = 13, ClassRightNum = 14, ListSkin = "test", ContentSkin = "text" }; 11 Models.CmsMiee_Article_Category cate9 = new Models.CmsMiee_Article_Category() { Name = "电冰箱", ClassLeftNum = 15, ClassRightNum = 16, ListSkin = "test", ContentSkin = "text" }; 12 cManager.Add(cate1); 13 cManager.Add(cate2); 14 cManager.Add(cate3); 15 cManager.Add(cate4); 16 cManager.Add(cate5); 17 cManager.Add(cate6); 18 cManager.Add(cate7); 19 cManager.Add(cate8); 20 cManager.Add(cate9); 21 return new MvcHtmlString("OK"); 22 23 //整体数据,后面涉及一些基本操作所调用的实体有些就是用的这个 24 long nodeId = 315; 25 Models.CmsMiee_Article_Category cate = cManager.GetById(nodeId); 26 //一、计算A节点的子节点数。 $num = ($AR - $AL -1)/2; 27 return Json((cate.ClassRightNum - cate.ClassLeftNum - 1) / 2, JsonRequestBehavior.AllowGet); 28 29 //二、查找A节点的所有子节点。 30 select * from tree where L > $AL and R < $AR order by L asc; 31 List<Models.CmsMiee_Article_Category> childCate = cManager.GetListByCondition(c => c.ClassLeftNum > cate.ClassLeftNum && c.ClassRightNum < cate.ClassRightNum, c => c.ClassLeftNum); 32 return Json(childCate, JsonRequestBehavior.AllowGet); 33 34 //三、查找A节点的所有父节点。 35 select * from tree where L < $AL and R > $AR order by L desc; 36 List<Models.CmsMiee_Article_Category> parentCate = cManager.GetListByCondition(c => c.ClassLeftNum < cate.ClassLeftNum && c.ClassRightNum > cate.ClassRightNum, c => c.Id); 37 string r1 = ""; 38 foreach (Models.CmsMiee_Article_Category c in parentCate) 39 { 40 r1 += "," + c.Name; 41 } 42 return new MvcHtmlString(r1); 43 44 //四、在A节点下增加子节点B,B作为最后一个子节点。 45 update tree set L = L + 2 where L >= $AR; 46 update tree set R = R + 2 where R >= $AR; 47 insert into tree (name, L, R) values(‘B‘, $AR-1, $AR); 48 List<Models.CmsMiee_Article_Category> update1 = cManager.GetListByCondition(c => c.ClassLeftNum >= cate.ClassRightNum, c => c.ClassLeftNum); 49 List<Models.CmsMiee_Article_Category> update2 = cManager.GetListByCondition(c => c.ClassRightNum >= cate.ClassRightNum, c => c.ClassLeftNum); 50 foreach (Models.CmsMiee_Article_Category c in update1) 51 { 52 c.ClassLeftNum += 2; 53 cManager.Modify(c, "ClassLeftNum"); 54 } 55 foreach (Models.CmsMiee_Article_Category c in update2) 56 { 57 c.ClassRightNum += 2; 58 cManager.Modify(c, "ClassRightNum"); 59 } 60 Models.CmsMiee_Article_Category newClass = new Models.CmsMiee_Article_Category() { Name = "北极企鹅", ClassLeftNum = cate.ClassRightNum - 2, ClassRightNum = cate.ClassRightNum - 1, ListSkin = "test", ContentSkin = "text" }; 61 cManager.Add(newClass); 62 return Json("OK", JsonRequestBehavior.AllowGet); 63 64 //五、输出节点下的所有子节点,并提供层级等信息以便生成节点树 65 List<Models.CmsMiee_Article_Category> childCate = cManager.GetListByCondition(c => c.ClassLeftNum >= cate.ClassLeftNum && c.ClassRightNum <= cate.ClassRightNum, c => c.ClassRightNum); 66 List<Models.CmsMiee_Article_Category_Layer> cateList = new List<Models.CmsMiee_Article_Category_Layer>(); 67 foreach (Models.CmsMiee_Article_Category c in childCate) 68 { 69 Models.CmsMiee_Article_Category_Layer newCate = new Models.CmsMiee_Article_Category_Layer(); 70 newCate.Id = c.Id; 71 newCate.Name = c.Name; 72 newCate.ClassLeftNum = c.ClassLeftNum; 73 newCate.ClassRightNum = c.ClassRightNum; 74 newCate.ListSkin = c.ListSkin; 75 newCate.ContentSkin = c.ContentSkin; 76 newCate.AddTime = c.AddTime; 77 newCate.DelTime = c.DelTime; 78 newCate.IsDeleted = c.IsDeleted; 79 newCate.Layer = cManager.GetListByCondition(c1 => c1.ClassLeftNum <= newCate.ClassLeftNum && c1.ClassRightNum >= newCate.ClassRightNum, c1 => c.ClassLeftNum).Count; 80 cateList.Add(newCate); 81 } 82 //拼接节点树 83 string tree = ""; 84 foreach (Models.CmsMiee_Article_Category_Layer cl in cateList) 85 { 86 string tab = ""; 87 //根据层级生成制表符 88 for (int index = 0; index < cl.Layer; index++) { tab += " "; } 89 tree += tab + cl.Name + " - 层级:" + cl.Layer + "\n"; 90 } 91 MvcHtmlString result = new MvcHtmlString("<pre>" + tree + "</pre>"); 92 return result; 93 94 //六、删除A节点。先要计出该节点及其所有子节点所占的左右值空间,将这些节点删掉,然后更新其它节点的左右值。 95 $num = $AR - $AL + 1; 96 delete from tree where L >= $AL and R <= $AR; 97 update tree set R = R - $num where R > $AR; 98 update tree set = L - $num where L > $AR; 99 long cateLAR = cate.ClassRightNum - cate.ClassLeftNum + 1; 100 cManager.DelByCondition(c => c.ClassLeftNum >= cate.ClassLeftNum && c.ClassRightNum <= cate.ClassRightNum); 101 List<Models.CmsMiee_Article_Category> update1 = cManager.GetListByCondition(c => c.ClassRightNum > cate.ClassRightNum, c => c.ClassRightNum); 102 List<Models.CmsMiee_Article_Category> update2 = cManager.GetListByCondition(c => c.ClassLeftNum > cate.ClassRightNum, c => c.ClassRightNum); 103 foreach (Models.CmsMiee_Article_Category c in update1) 104 { 105 c.ClassRightNum -= cateLAR; 106 cManager.Modify(c, "ClassRightNum"); 107 } 108 foreach (Models.CmsMiee_Article_Category c in update2) 109 { 110 c.ClassLeftNum -= cateLAR; 111 cManager.Modify(c, "ClassLeftNum"); 112 } 113 MvcHtmlString result = new MvcHtmlString("OK"); 114 return result; 115 116 //七、分类的父级修改 117 //1.如果目标节点的ClassRightNum小于当前节点的ClassRightNum;并且目标节点的ClassLeftNum大于当前节点的ClassLeftNum,则返回第一个错误: 118 long selfCategoryId = 316; //要移动的节点 119 long newCategoryId = 321; //目标节点 120 Models.CmsMiee_Article_Category selfCategory = cManager.GetById(selfCategoryId); 121 Models.CmsMiee_Article_Category newCategory = cManager.GetById(newCategoryId); 122 if (selfCategory == null) return new MvcHtmlString("当前所操作的分类不存在!"); 123 if (newCategory == null) return new MvcHtmlString("您选择的新分类不存在!"); 124 long selfLeft = selfCategory.ClassLeftNum; 125 long selfRight = selfCategory.ClassRightNum; 126 long value = selfRight - selfLeft; 127 //取得该分类下面的所有分类,包括自身 128 List<Models.CmsMiee_Article_Category> selfCategories = cManager.GetListByCondition(c => c.ClassLeftNum >= selfLeft && c.ClassRightNum <= selfRight, c => c.Id); 129 //将所有分类的ID写入数组以便更新左右值 130 long[] selfCategoryIDS = new long[selfCategories.Count]; 131 for (int index = 0; index < selfCategoryIDS.Length; index++) 132 { 133 selfCategoryIDS[index] = Convert.ToInt32(selfCategories[index].Id); 134 } 135 //将所有子类及自身的id组成字符串,逗号分隔 136 string inIDS = string.Join(",", selfCategoryIDS); 137 long parentLeft = newCategory.ClassLeftNum; 138 long parentRight = newCategory.ClassRightNum; 139 //读取新父级分类的所有父级分类及其层级 140 List<Models.CmsMiee_Article_Category> newParentCate1 = cManager.GetListByCondition(c => c.ClassLeftNum < newCategory.ClassLeftNum && c.ClassRightNum > newCategory.ClassRightNum, c => c.Id); 141 List<Models.CmsMiee_Article_Category_Layer> newParentCate = new List<Models.CmsMiee_Article_Category_Layer>(); 142 foreach (Models.CmsMiee_Article_Category c in newParentCate1) 143 { 144 Models.CmsMiee_Article_Category_Layer newCate = new Models.CmsMiee_Article_Category_Layer(); 145 newCate.Id = c.Id; 146 newCate.Name = c.Name; 147 newCate.ClassLeftNum = c.ClassLeftNum; 148 newCate.ClassRightNum = c.ClassRightNum; 149 newCate.ListSkin = c.ListSkin; 150 newCate.ContentSkin = c.ContentSkin; 151 newCate.AddTime = c.AddTime; 152 newCate.DelTime = c.DelTime; 153 newCate.IsDeleted = c.IsDeleted; 154 newCate.Layer = cManager.GetListByCondition(c1 => c1.ClassLeftNum <= newCate.ClassLeftNum && c1.ClassRightNum >= newCate.ClassRightNum, c1 => c.ClassLeftNum).Count; 155 newParentCate.Add(newCate); 156 } 157 //判断是前移还是后移,并更新数据库 158 if (parentRight > selfRight) 159 { 160 //后移 161 //更新左边值 162 //update CmsMiee_Article_Category set ClassLeftNum=ClassLeftNum-value-1 where ClassLeftNum>selfRight and ClassRightNum<=parentRight 163 List<Models.CmsMiee_Article_Category> tempCategories = cManager.GetListByCondition(c => c.ClassLeftNum > selfRight && c.ClassRightNum <= parentRight, c => c.Id); 164 foreach (Models.CmsMiee_Article_Category c in tempCategories) 165 { 166 c.ClassLeftNum = c.ClassLeftNum - value - 1; 167 cManager.Modify(c, "ClassLeftNum"); 168 } 169 //更新新父类的父类的左边值 170 foreach (Models.CmsMiee_Article_Category_Layer c in newParentCate) 171 { 172 if (c.Layer == 1) continue; 173 c.ClassLeftNum = c.ClassLeftNum - value - 1; 174 //转换为不带层级的分类后更新到数据库中 175 Models.CmsMiee_Article_Category result = cManager.GetById(c.Id); 176 result.ClassLeftNum = c.ClassLeftNum; 177 cManager.Modify(result, "ClassLeftNum"); 178 } 179 //update CmsMiee_Article_Category set ClassRightNum=ClassRightNum-value-1 where ClassRightNum>selfRight and ClassRightNum<parentRight 180 //更新右边值 181 tempCategories = cManager.GetListByCondition(c => c.ClassRightNum > selfRight && c.ClassRightNum < parentRight, c => c.Id); 182 foreach (Models.CmsMiee_Article_Category c in tempCategories) 183 { 184 c.ClassRightNum = c.ClassRightNum - value - 1; 185 cManager.Modify(c, "ClassRightNum"); 186 } 187 long tempValue = parentRight - selfRight - 1; 188 tempCategories = cManager.GetListByCondition(c => selfCategoryIDS.Contains(c.Id), c => c.Id); 189 //update CmsMiee_Article_Category set ClassLeftNum=ClassLeftNum+tempValue,ClassRightNum=ClassRightNum+tempValue where Id in(selfCategoryIDS) 190 foreach (Models.CmsMiee_Article_Category c in tempCategories) 191 { 192 c.ClassLeftNum = c.ClassLeftNum + tempValue; 193 c.ClassRightNum = c.ClassRightNum + tempValue; 194 cManager.Modify(c, "ClassLeftNum", "ClassRightNum"); 195 } 196 } 197 else 198 { 199 //前移 200 List<Models.CmsMiee_Article_Category> tempCategories = cManager.GetListByCondition(c => c.ClassLeftNum > parentRight && c.ClassLeftNum < selfLeft, c => c.Id); 201 //更新左边值 202 foreach (Models.CmsMiee_Article_Category c in tempCategories) 203 { 204 c.ClassLeftNum = c.ClassLeftNum + value + 1; 205 cManager.Modify(c, "ClassLeftNum"); 206 } 207 //更新右边值 208 tempCategories = cManager.GetListByCondition(c => c.ClassRightNum >= parentRight && c.ClassRightNum < selfLeft, c => c.Id); 209 foreach (Models.CmsMiee_Article_Category c in tempCategories) 210 { 211 c.ClassRightNum = c.ClassRightNum + value + 1; 212 cManager.Modify(c, "ClassRightNum"); 213 } 214 long tempValue = selfLeft - parentRight; 215 tempCategories = cManager.GetListByCondition(c => selfCategoryIDS.Contains(c.Id), c => c.Id); 216 foreach (Models.CmsMiee_Article_Category c in tempCategories) 217 { 218 c.ClassLeftNum = c.ClassLeftNum - tempValue; 219 c.ClassRightNum = c.ClassRightNum - tempValue; 220 cManager.Modify(c, "ClassLeftNum", "ClassRightNum"); 221 } 222 } 223 return new MvcHtmlString("操作完成!");
估计是特别乱了,昨天整理了好久,总算是放到DAL里面去了,最后一个修改的功能,步骤稍微有点繁琐。为以防万一,我用的是事务,反正很简单,SaveChange你懂的》。。。
变量里面用到的cManager对象是BLL中管理分类用的类,没有什么特别,只是继承了父类的增删改查功能。
这段代码只是我测试、学习的时候用到的,后来改动了很多地方,不过关于数据库操作和无限级分类这一块,基本上没什么改动了。没这么无私,所以懒得整理了(PS:我要是像大神们那样整理,估计代码中也会“恰巧”出现一点点关键地方的错误了,呵呵)。所以需要用的朋友可以自行整理一下。
时间: 2024-10-14 09:34:23