zoukankan      html  css  js  c++  java
  • 左右值无限级分类 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:我要是像大神们那样整理,估计代码中也会“恰巧”出现一点点关键地方的错误了,呵呵)。所以需要用的朋友可以自行整理一下。

  • 相关阅读:
    【PAT甲级】1043 Is It a Binary Search Tree (25 分)(判断是否为BST的先序遍历并输出后序遍历)
    Educational Codeforces Round 73 (Rated for Div. 2)F(线段树,扫描线)
    【PAT甲级】1042 Shuffling Machine (20 分)
    【PAT甲级】1041 Be Unique (20 分)(多重集)
    【PAT甲级】1040 Longest Symmetric String (25 分)(cin.getline(s,1007))
    【PAT甲级】1039 Course List for Student (25 分)(vector嵌套于map,段错误原因未知)
    Codeforces Round #588 (Div. 2)E(DFS,思维,__gcd,树)
    2017-3-9 SQL server 数据库
    2017-3-8 学生信息展示习题
    2017-3-5 C#基础 函数--递归
  • 原文地址:https://www.cnblogs.com/jiangkun/p/Infinite_Class_MVC_EntityFramework.html
Copyright © 2011-2022 走看看