左右值无限级分类 MVC + EntityFramework 的简单实现

  在度娘上查了大半个月的资料,最后发现每个网友分享的文章都有一定的错误(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

左右值无限级分类 MVC + EntityFramework 的简单实现的相关文章

php利用递归函数实现无限级分类

相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径.各种对商品分类,商品名之类的操作应该是得心应手,那么就可以尝试下无限级分类列表的制作了. 什么是无限级分类? 无限级分类是一种分类技巧,例如部门组织,文章分类,学科分类等常用到无限级分类,将其简单理解成分类就好了.其实我们仔细想一下,生活中的分类简直太多了,衣服可以分为男装和女装,也可以分为上衣和裤子,也可以根据年龄段分类.分类无处不在,分类显得“无限”.我这里就不说无限分类的必要性了. 无限级分类原理简介 无限分类看

(实用篇)PHP递归实现无限级分类

在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 递归,简单的说就是一段程序代码的重复调用,当把代码写到一个自定义函数中,将参数等变量保存,函数中重复调用函数,直到达到某个条件才跳出,返回相应的数据. 首先

PHP无限级分类-递归(不推荐)

[http://www.helloweba.com/view-blog-204.html] 在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 递归,简单的说就是一段程序代码的重复调用,当把代码写到一个自定义

php实现无限级分类(递归方法)

什么是无限级分类? 无限级分类是一种分类技巧,例如部门组织,文章分类,学科分类等常用到无限级分类, 将其简单理解成分类就好了.其实我们仔细想一下,生活中的分类简直太多了, 衣服可以分为男装和女装,也可以分为上衣和裤子,也可以根据年龄段分类. 分类无处不在,分类显得"无限".我这里就不说无限分类的必要性了. 无限级分类原理简介 无限分类不仅仅需要代码的巧妙性,也要依托数据库设计的合理性. 要满足无限级分类,数据库需要有两个必须的字段id,pid. id用来标识自身,而pid则是用来表明父

PHP递归实现无限级分类

在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 递归,简单的说就是一段程序代码的重复调用,当把代码写到一个自定义函数中,将参数等变量保存,函数中重复调用函数,直到达到某个条件才跳出,返回相应的数据. My

PHP利用递归函数实现无限级分类的方法_php技巧 - PHP

文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径.各种对商品分类,商品名之类的操作应该是得心应手,那么就可以尝试下无限级分类列表的制作了. 什么是无限级分类? 无限级分类是一种分类技巧,例如部门组织,文章分类,学科分类等常用到无限级分类,将其简单理解成分类就好了.其实我们仔细想一下,生活中的分类简直太多了,衣服可以分为男装和女装,也可以分为上衣和裤子,也可以根据年龄段分类.分类无处不在,分

左右值编码,文章类别。无限级分类

在网上也搜了很多的例子,根据网络上的解释,慢慢摸索,用了将近2周的时间.笨人,没办法.有什么错的 请留言哦. 在yii php框架下 无限级分类. 通过网络上的,我们都了解到 实现文章 无限级分类,可以使用左右值编码,是通过二叉树的先序遍历 来得到 类别的,不使用递归.这种方法在 全部查询出 类别的时候,是很简单的. 先看数据库表格的设计. id name lft rht father_id layer 1 顶级分类 1 4 0 0 2 网站底部 2 3 1 1 注释: id --- 类别id

mysql 无限级分类实现思路

第一种方案: 使用递归算法,也是使用频率最多的,大部分开源程序也是这么处理,不过一般都只用到四级分类. 这种算法的数据库结构设计最为简单.category表中一个字段id,一个字段fid(父id).这样可以根据WHERE id = fid来判断上一级内容,运用递归至最顶层. 分析:通过这种数据库设计出的无限级,可以说读取的时候相当费劲,所以大部分的程序最多3-4级分类,这就足以满足需求,从而一次性读出所有的数据,再对得到数组或者对象进行递归.本身负荷还是没太大问题.但是如果分类到更多级,那是不可

php无限级分类实战——评论及回复功能

经常在各大论坛或新闻板块详情页面下边看到评论功能,当然不单单是直接发表评论内容那么简单, 可以对别人的评论进行回复,别人又可以对你的回复再次评论或回复,如此反复,理论上可以说是 没有休止,从技术角度分析很容易想到运用无限级分类技术存储数据,运用递归获取评论层级结构 数据,运用ajax实现评论页面交互,这里用thinkphp框架做个简单的demo练练手,为了简化流程 这里第三级评论不再提供回复功能,当然只要在这个基础上稍作修改就可以实现无限回复功能,主 要是view层样式修改较麻烦,需花些时间.