关系数据库中存储树形结构

原理:

我们先把树按照水平方式摆开。从根节点开始(“Food”),然后他的左边写上1。然后按照树的顺序(从上到下)给“Fruit”的左边写上2。这样,你沿着树的边界走啊走(这就是“遍历”),然后同时在每个节点的左边和右边写上数字。最后,我们回到了根节点“Food”在右边写上18。下面是标上了数字的树,同时把遍历的顺序用箭头标出来了。

  我们称这些数字为左值和右值(如,“站点”的左值是1,右值是16)。正如你所见,这些数字按时了每个节点之间的关系。因为“流量计”有3和6两个值,所以,它是有拥有1-16值的“站点”节点的后续。同样的,我们可以推断所有左值大于2并且右值小于9的节点,都是有2-9的“门站t” 节点的后续。这样,树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做“改进前序遍历树”算法。

数据库表结构设计如下:

解释一下每个字段的意思

id 唯一值,自动增长,主键

parent 当前节点父节点的名称

name 当前节点名

扫描二维码关注公众号,回复: 3761164 查看本文章

lft 左值

rgt 右值

type 节点类型,节点类型分为 0=根节点,1=站点,2=分组,3=参数点名称

paramkey  连接另外一个表的关键值

unit  连接的参数值的单位

数据表内容如下:

参数中用到了一个TreeNodeInfo类,这个类是自定义类型成员如下:

 /// <summary>
    ///数据库中节点数据的实体类
    /// </summary>
    class TreeNodeInfo
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public TreeNodeInfo()
        {
            this.ParamKey = "";
            this.ParentName = "";
            this.NodeName = "";
            this.Unit = "";
            this.LeafType = LeafNodeType.Group;
        }
        /// <summary>
        /// ID
        /// </summary>
        public int ID
        {
            get;
            set;
        }
        /// <summary>
        /// 当前节点名称
        /// </summary>
        public string NodeName
        {
            get;
            set;
        }
        /// <summary>
        /// 父节点名称
        /// </summary>
        public string ParentName
        {
            get;
            set;
        }
        /// <summary>
        /// 当前节点左边编号
        /// </summary>
        public int  Lft
        {
            get;
            set;
        }
        /// <summary>
        /// 当前节点右编号值
        /// </summary>
        public int Rgt
        {
            get;
            set;
        }
        /// <summary>
        /// 节点类型
        /// </summary>
        public LeafNodeType LeafType
        {
            get;
            set;
        }
        /// <summary>
        /// 参数点的名称
        /// </summary>
        public string ParamKey
        {
            get;
            set;
        }
        /// <summary>
        /// 节点连接的SCADA系统的参数点信息
        /// </summary>
        public object Tag
        {
            get;
            set;
        }
        /// <summary>
        /// 节点在树中的深度,重零开始
        /// </summary>
        public int Level
        {
            get;
            set;
        }
        /// <summary>
        /// 参数点单位
        /// </summary>
        public string Unit
        {
            get;
            set;
        }
    }

       /// <summary>
        /// 插入节点
        /// </summary>
        /// <param name="parentNodeName">父节点名称</param>
        /// <param name="currentNodeName">当前节点名称</param>
        /// <param name="parentNodePath">父节点路径</param>
        /// <param name="currentNodePath">当前节点路径</param>
        /// <param name="type">节点类型</param>
        /// <param name="paramkey">连接参数点名称</param>
        /// <returns>插入成功标志</returns>

       public  bool InsertNode(string parentNodeName, string currentNodeName,string parentNodePath,string currentNodePath,TreeNodeInfo nodeInfo)
        {
            bool succeed=true ;
            //先实例SqlTransaction类,使用这个事务使用的是con 这个连接,使用BeginTransaction这个方法来开始执行这个事务
            SqlTransaction tran = null;
            SqlConnection conn = null;
            try
            {
                if (!parentNodePath.Equals(currentNodePath))
                {
                    //插入子节点
                    int id = NodeID(parentNodeName, parentNodePath);
                    if (id > -1)
                    {
                        string sql = "SELECT rgt FROM t_nested_category WHERE id = @id";
                        int myrgh = 0;
                        SqlParameter[] parameter = new SqlParameter[1];
                        parameter[0] = new SqlParameter("id", id);
                        SqlDataReader reader = MSQLHelper.ExecuteReader(CommandType.Text, sql, parameter);
                        if (reader.Read())
                        {
                            myrgh = reader.GetInt32(0);
                        }
                        reader.Close();

                        conn = new SqlConnection(MSQLHelper.CONN_STRING);
                        conn.Open();
                        tran = conn.BeginTransaction();
                        SqlCommand cmd = new SqlCommand();
                        cmd.Connection = conn;
                        cmd.Transaction = tran;

                        string sql2 = "update t_nested_category SET rgt = rgt + 2 WHERE rgt >= @myRight";
                        cmd.CommandText = sql2;
                        cmd.Parameters.Add(new SqlParameter("myRight", myrgh));
                        cmd.Parameters.Add(new SqlParameter("currentNodeName", currentNodeName));
                        cmd.Parameters.Add(new SqlParameter("parentNodeName", parentNodeName));
                        cmd.Parameters.Add(new SqlParameter("type", (int)nodeInfo.LeafType ));
                        cmd.Parameters .Add (new SqlParameter ("paramkey",nodeInfo.ParamKey));
                        cmd.Parameters .Add (new SqlParameter ("unit",nodeInfo .Unit));
                        cmd.Parameters["type"].Value = (int)nodeInfo.LeafType;
                        int n = cmd.ExecuteNonQuery();

                        string sql3 = "update t_nested_category set lft = lft + 2 WHERE lft >= @myRight";
                        cmd.CommandText = sql3;
                        n = cmd.ExecuteNonQuery();

                        string sql4 = "INSERT INTO t_nested_category(parent,name, lft, rgt,type,paramkey,unit) VALUES(@parentNodeName,@currentNodeName, @myRight, @myRight + 1,@type,@paramkey,@unit)";
                        cmd.CommandText = sql4;
                        n = cmd.ExecuteNonQuery();
                        tran.Commit();

                    }
                }
                else
                {
                    //插入根节点
                    conn = new SqlConnection(MSQLHelper.CONN_STRING);
                    conn.Open();
                    tran = conn.BeginTransaction();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = conn;
                    cmd.Transaction = tran;
                    string sql4 = "INSERT INTO t_nested_category(parent,name, lft, rgt,type,paramkey,unit) VALUES(@parentNodeName,@currentNodeName, @myRight, @myRight + 1,@type,@paramkey,@unit)";
                    cmd.CommandText = sql4;
                    cmd.Parameters.Add(new SqlParameter("myRight", 1));
                    cmd.Parameters.Add(new SqlParameter("currentNodeName", currentNodeName));
                    cmd.Parameters.Add(new SqlParameter("parentNodeName", parentNodeName));
                    cmd.Parameters.Add(new SqlParameter("type", (int)LeafNodeType.Root));
                    cmd.Parameters .Add (new SqlParameter ("paramkey",nodeInfo.ParamKey));
                    cmd.Parameters.Add (new SqlParameter ("unit",nodeInfo.Unit ));
                    cmd.Parameters["type"].Value = (int)LeafNodeType.Root;
                    int n = cmd.ExecuteNonQuery();
                    tran.Commit();
                }
            }
            catch (SqlException ex)
            {
                succeed = false;
                log.Error(ex.Message);
                if (tran != null)
                {
                    tran.Rollback();
                }
            }
            catch (Exception ex)
            {
                succeed = false;
                log.Error(ex.Message);
                if (tran != null)
                {
                    tran.Rollback();
                }
            }
            finally
            {
                if (conn != null)
                {
                    conn.Close();
                    tran.Dispose();
                    conn.Dispose();
                }
            }  

            return succeed;
        }

       /// <summary>
        /// 设置当前节点在父节点中的索引位置
        /// </summary>
        /// <param name="currentNodeName">当前节点名称</param>
        /// <param name="curretnNodePath">当前节点名称路径</param>
        /// <param name="parentNodeName">当前节点父节点名称</param>
        ///<param name="parentNodePath">当前节点父节点路径</param>
        ///<param name="index">节点索引</param>

      public void SetNodeIndex(string parentNodeName, string currentNodeName, string parentNodePath, string curretnNodePath, int index)
        {
            //事务
            SqlTransaction tran = null;
            //连接
            SqlConnection conn = null;
            try
            {
                DataTable dt = SubTree(parentNodeName, parentNodePath);
                if (dt != null)
                {
                    if (index < 0)
                    {
                        index = 0;

                    }
                    else if (dt.Rows.Count < index)
                    {
                        index = dt.Rows.Count - 1;
                    }

                    TreeNodeInfo destNode = new TreeNodeInfo();
                    //设定将要移动到的目标节点位置的节点属性
                    destNode.ID = Convert.ToInt32(dt.Rows[index]["id"]);
                    destNode.LeafType = (LeafNodeType)Convert.ToInt32(dt.Rows[index]["type"]);
                    destNode.Lft = Convert.ToInt32(dt.Rows[index]["lft"]);
                    destNode.Rgt = Convert.ToInt32(dt.Rows[index]["rgt"]);
                    destNode.NodeName = dt.Rows[index]["name"].ToString();
                    destNode.ParentName = dt.Rows[index]["parent"].ToString();
                    destNode.ParamKey = dt.Rows[index]["paramkey"].ToString();
                    destNode.Unit = dt.Rows[index]["unit"].ToString();
                    TreeNodeInfo sourceNdoe = new TreeNodeInfo();
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        string name = dt.Rows[i]["name"].ToString();
                        if (name.Equals(currentNodeName))
                        {
                            //设置源节点属性
                            sourceNdoe.ID = Convert.ToInt32(dt.Rows[i]["id"]);
                            sourceNdoe.LeafType = (LeafNodeType)Convert.ToInt32(dt.Rows[i]["type"]);
                            sourceNdoe.Lft = Convert.ToInt32(dt.Rows[i]["lft"]);
                            sourceNdoe.Rgt = Convert.ToInt32(dt.Rows[i]["rgt"]);
                            sourceNdoe.NodeName = dt.Rows[i]["name"].ToString();
                            sourceNdoe.ParentName = dt.Rows[i]["parent"].ToString();
                            sourceNdoe.ParamKey = dt.Rows[i]["paramkey"].ToString();
                            sourceNdoe.Unit = dt.Rows[i]["unit"].ToString();
                            break;
                        }
                    }
                    //将左值最小的节点设置为目标节点
                    if (destNode.Lft > sourceNdoe.Lft)
                    {
                        TreeNodeInfo temp = new TreeNodeInfo();
                        temp.ID = destNode.ID;
                        temp.LeafType = destNode.LeafType;
                        temp.Lft = destNode.Lft;
                        temp.Rgt = destNode.Rgt;
                        temp.NodeName = destNode.NodeName;
                        temp.ParentName = destNode.ParentName;
                        temp.ParamKey = destNode.ParamKey;
                        temp.Unit = destNode.Unit;

                        destNode.ID = sourceNdoe.ID;
                        destNode.LeafType = sourceNdoe.LeafType;
                        destNode.Lft = sourceNdoe.Lft;
                        destNode.Rgt = sourceNdoe.Rgt;
                        destNode.NodeName = sourceNdoe.NodeName;
                        destNode.ParentName = sourceNdoe.ParentName;
                        destNode.ParamKey = sourceNdoe.ParamKey;
                        destNode.Unit = sourceNdoe.Unit;

                        sourceNdoe.ID = temp.ID;
                        sourceNdoe.LeafType = temp.LeafType;
                        sourceNdoe.Lft = temp.Lft;
                        sourceNdoe.Rgt = temp.Rgt;
                        sourceNdoe.NodeName = temp.NodeName;
                        sourceNdoe.ParentName = temp.ParentName;
                        sourceNdoe.ParamKey = temp.ParamKey;
                        sourceNdoe.Unit = temp.Unit;

                        currentNodeName = sourceNdoe.NodeName;
                        curretnNodePath = parentNodePath + "\\" + currentNodeName;

                    }
                    TreeNodeInfo parentNode = new TreeNodeInfo();
                    int id = NodeID(parentNodeName, parentNodePath);
                    if (id > -1)
                    {
                        string sql = "SELECT *  FROM t_nested_category WHERE id =@id";

                        SqlParameter[] parameter = new SqlParameter[1];
                        parameter[0] = new SqlParameter("id", id);
                        parameter[0].Value = id;
                        SqlDataReader reader = MSQLHelper.ExecuteReader(CommandType.Text, sql, parameter);
                        if (reader.Read())
                        {
                            parentNode.ID = reader.GetInt32(0);
                            parentNode.ParentName = reader.GetString(1);
                            parentNode.NodeName = reader.GetString(2);
                            parentNode.Lft = reader.GetInt32(3);
                            parentNode.Rgt = reader.GetInt32(4);
                            parentNode.LeafType = (LeafNodeType)reader.GetInt32(5);
                            parentNode.ParamKey = reader.GetString(6);
                            parentNode.Unit = reader.GetString(7);
                        }
                        reader.Close();

                        //获得源节点
                        DataTable sourceTable = FullTreeByNodeName(currentNodeName, curretnNodePath);
                        //数据库中删除源节点,为了重新设置源节点的位置
                        DeleteNode(currentNodeName, curretnNodePath, false);

                        int n = -1;
                        conn = new SqlConnection(MSQLHelper.CONN_STRING);
                        conn.Open();
                        tran = conn.BeginTransaction();
                        SqlCommand cmd = new SqlCommand();
                        cmd.Connection = conn;
                        cmd.Transaction = tran;
                        cmd.Parameters.Add(new SqlParameter("myLeft", destNode.Lft));
                        cmd.Parameters.Add(new SqlParameter("myWidth", sourceTable.Rows.Count * 2));
                        cmd.Parameters.Add(new SqlParameter("soucrelft", sourceNdoe.Lft));
                        cmd.Parameters.Add(new SqlParameter("soucrergt", sourceNdoe.Rgt));
                        string sql3 = "UPDATE t_nested_category SET rgt = rgt + @myWidth WHERE rgt >= @myLeft and  rgt< @soucrelft ";
                        cmd.CommandText = sql3;
                        n = cmd.ExecuteNonQuery();
                        string sql4 = "UPDATE t_nested_category SET lft = lft + @myWidth WHERE lft >= @myLeft and  lft< @soucrelft";
                        cmd.CommandText = sql4;
                        n = cmd.ExecuteNonQuery();

                        //将源节点的值重新插入数据库中
                        cmd.Parameters.Add(new SqlParameter("parentNodeName", SqlDbType.NVarChar));
                        cmd.Parameters.Add(new SqlParameter("currentNodeName", SqlDbType.NVarChar));
                        cmd.Parameters.Add(new SqlParameter("myRight", SqlDbType.Int));
                        cmd.Parameters.Add(new SqlParameter("type", SqlDbType.Int));
                        cmd.Parameters.Add(new SqlParameter("paramkey", SqlDbType.NVarChar));
                        cmd.Parameters.Add(new SqlParameter("unit", SqlDbType.NVarChar));
                        string sql5 = "INSERT INTO t_nested_category(parent,name, lft, rgt,type,paramkey,unit) VALUES(@parentNodeName,@currentNodeName, @myLeft, @myRight,@type,@paramkey,@unit)";
                        cmd.CommandText = sql5;
                        for (int i = 0; i < sourceTable.Rows.Count; i++)
                        {
                            cmd.Parameters["parentNodeName"].Value = sourceTable.Rows[i]["parent"];
                            cmd.Parameters["currentNodeName"].Value = sourceTable.Rows[i]["name"];
                            cmd.Parameters["myLeft"].Value = Convert.ToInt32(sourceTable.Rows[i]["lft"]) - (sourceNdoe.Lft - destNode.Lft);
                            cmd.Parameters["myRight"].Value = Convert.ToInt32(sourceTable.Rows[i]["rgt"]) - (sourceNdoe.Lft - destNode.Lft);
                            cmd.Parameters["type"].Value = sourceTable.Rows[i]["type"];
                            cmd.Parameters["paramkey"].Value = sourceTable.Rows[i]["paramkey"];
                            cmd.Parameters["unit"].Value = sourceTable.Rows[i]["unit"];
                            n = cmd.ExecuteNonQuery();
                        }
                        tran.Commit();
                    }
                }
                else
                {
                    throw new Exception("节点数不正确!");
                }

            }
            catch (Exception ex)
            {

                log.Error(ex.StackTrace);
                tran.Rollback();
                throw ex;
            }
            finally
            {
                if (conn != null)
                {
                    conn.Close();
                    tran.Dispose();
                    conn.Dispose();
                }
            }
        }

 /// <summary>
        /// 删除当前节点
        /// </summary>
        /// <param name="currentNodeName">当前节点名称</param>
        /// <param name="currentNodePath">当前节点路径</param>
        ///  <param name="Recursive">删除节点是是否递归改变整个树中应该被改变的值,为False 时常用于同级节点的移动</param>
        /// <returns>删除成功标志</returns>
        public bool DeleteNode(string currentNodeName, string currentNodePath, bool Recursive)
        {
            bool succeed = true;
            //先实例SqlTransaction类,使用这个事务使用的是con 这个连接,使用BeginTransaction这个方法来开始执行这个事务
            SqlTransaction tran = null;
            SqlConnection conn = null;
            try
            {
                int id = NodeID(currentNodeName, currentNodePath);
                if (id > -1)
                {
                    string sql = "SELECT lft,rgt, rgt - lft + 1 FROM t_nested_category WHERE id=@id";
                    int mylft = 0, myrgh = 0, mywidth = 0;
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    parameter[0].Value = id;
                    SqlDataReader reader = MSQLHelper.ExecuteReader(CommandType.Text, sql, parameter);
                    if(reader.Read())
                    {
                        mylft = reader.GetInt32(0);
                        myrgh = reader.GetInt32(1);
                        mywidth = reader.GetInt32(2);
                    }
                    reader.Close();
                    conn = new SqlConnection(MSQLHelper.CONN_STRING);
                    conn.Open();
                    tran = conn.BeginTransaction();
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = conn;
                    cmd.Transaction = tran;

                    string sql2 = "DELETE FROM t_nested_category WHERE lft BETWEEN @myLeft AND @myRight";
                    cmd.CommandText = sql2;
                    cmd.Parameters.Add(new SqlParameter("myLeft", mylft));
                    cmd.Parameters.Add(new SqlParameter("myRight", myrgh));
                    cmd.Parameters.Add(new SqlParameter("myWidth ", mywidth));
                    int n = cmd.ExecuteNonQuery();
                    if (Recursive)
                    {
                        string sql3 = "UPDATE t_nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight";
                        cmd.CommandText = sql3;
                        n = cmd.ExecuteNonQuery();

                        string sql4 = "UPDATE t_nested_category SET lft = lft - @myWidth WHERE lft > @myRight";
                        cmd.CommandText = sql4;
                        n = cmd.ExecuteNonQuery();
                    }
                    tran.Commit();
                }
               
            }
            catch (SqlException ex)
            {
                succeed = false;
                log.Error(ex.Message);
                if (tran != null)
                {
                    tran.Rollback();
                }
            }
            catch (Exception ex)
            {
                succeed = false;
                log.Error(ex.Message);
                if (tran != null)
                {
                    tran.Rollback();
                }
            }
            finally
            {
                if (conn != null)
                {
                    conn.Close();
                    tran.Dispose();
                    conn.Dispose();
                }
            } 
            return succeed;
        }

 /// <summary>
        /// 更新节点信息
        /// </summary>
        /// <param name="currentNodeName">当前节点名称</param>
        /// <param name="currentNodePath">当前节点路径</param>
        /// <param name="nodeInfo">更新的节点信息</param>
        /// <returns></returns>
        public bool ModifyNode(string currentNodeName, string currentNodePath, TreeNodeInfo nodeInfo)
        {
            bool successed = false;
            SqlConnection conn = null;
            SqlTransaction tran = null;
            try
            {
                int id = NodeID(currentNodeName, currentNodePath);
                DataTable dt = SubTree(currentNodeName, currentNodePath);
                conn = new SqlConnection(MSQLHelper.CONN_STRING);
                conn.Open();
                tran = conn.BeginTransaction();
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = conn;
                cmd.Transaction = tran;
                cmd.Parameters.Add(new SqlParameter("name", SqlDbType.NVarChar));
                cmd.Parameters["name"].Value = nodeInfo.NodeName;
                cmd.Parameters.Add(new SqlParameter("parent", SqlDbType.NVarChar));
                cmd.Parameters["parent"].Value = nodeInfo.ParentName;
                cmd.Parameters.Add(new SqlParameter("type", SqlDbType.Int));
                cmd.Parameters["type"].Value = nodeInfo.LeafType;
                cmd.Parameters.Add(new SqlParameter("paramkey", SqlDbType.NVarChar));
                cmd.Parameters["paramkey"].Value = nodeInfo.ParamKey;
                cmd.Parameters.Add(new SqlParameter("id", SqlDbType.Int));
                cmd.Parameters["id"].Value = id;
                cmd.Parameters.Add(new SqlParameter("unit", SqlDbType.NVarChar));
                cmd.Parameters["unit"].Value = nodeInfo.Unit;
                cmd.CommandText = "update  t_nested_category  set name=@name,parent=@parent,type=@type,paramkey=@paramkey,unit=@unit where id=@id";
                int n = cmd.ExecuteNonQuery();
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    TreeNodeInfo nodeInfo2 = new TreeNodeInfo();
                    nodeInfo2.ID = Convert.ToInt32(dt.Rows[i]["id"]);
                    nodeInfo2.ParentName = nodeInfo.NodeName;
                    //参数赋值
                    cmd.Parameters["parent"].Value = nodeInfo2.ParentName;
                    cmd.Parameters["id"].Value = nodeInfo2.ID;
                    cmd.CommandText = "update t_nested_category set parent=@parent where id=@id";
                    n = cmd.ExecuteNonQuery();
                }
                if (n > 1)
                {
                    successed = true;
                }
                tran.Commit();
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                tran.Rollback();
                throw ex;
            }
            finally
            {
                if (conn != null)
                {
                    conn.Close();
                    tran.Dispose();
                    conn.Dispose();
                }
            }
            return successed;
        }
        /// <summary>
        /// 返回节点名称的树
        /// </summary>
        /// <param name="NodeName">节点名称</param>
        /// <param name="NodePath">当前节点路径</param>
        /// <returns></returns>
        public DataTable FullTreeByNodeName(string NodeName, string NodePath)
        {
            DataTable dt = null;
            try
            {
                int id = NodeID(NodeName, NodePath);
                if(id > -1)
                {
                    string sql = "SELECT T.*,V.level";
                    sql += " FROM (SELECT node.id,";
                    sql += "(COUNT(parent.name) - (AVG(sub_tree.level) + 1)) level ";
                    sql += " FROM t_nested_category node,";
                    sql += " t_nested_category parent,";
                    sql += " t_nested_category sub_parent,";
                    sql += "(SELECT V.* ";
                    sql += " FROM (SELECT node.id, (COUNT(parent.name) - 1) level ";
                    sql += " FROM t_nested_category node, t_nested_category parent";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.id = @id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ) sub_tree";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt";
                    sql += " AND sub_parent.id = sub_tree.id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ORDER BY T.Lft";
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
        /// <summary>
        /// 获得根节点开始的树
        /// </summary>
        /// <returns></returns>
        public DataTable FullTree()
        {
            DataTable dt = null;
            try
            {
                int id = NodeRootID();
                if (id > -1)
                {
                    string sql = "SELECT T.*,V.level";
                    sql += " FROM (SELECT node.id,";
                    sql += "(COUNT(parent.name) - (AVG(sub_tree.level) + 1)) level ";
                    sql += " FROM t_nested_category node,";
                    sql += " t_nested_category parent,";
                    sql += " t_nested_category sub_parent,";
                    sql += "(SELECT V.* ";
                    sql += " FROM (SELECT node.id, (COUNT(parent.name) - 1) level ";
                    sql += " FROM t_nested_category node, t_nested_category parent";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.id = @id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ) sub_tree";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt";
                    sql += " AND sub_parent.id = sub_tree.id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ORDER BY T.Lft";
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
        /// <summary>
        /// 返回当前节点子树
        /// </summary>
        /// <param name="NodeName">当前节点名称</param>
        /// <param name="NodePath">当前节点路径</param>
        /// <returns></returns>
        public DataTable SubTree(string NodeName, string NodePath)
        {
            DataTable dt = null;
            try
            {
                int id = NodeID(NodeName, NodePath);
                if (id > -1)
                {
                    string sql = "SELECT T.*,V.level";
                    sql += " FROM (SELECT node.id,";
                    sql += "(COUNT(parent.name) - (AVG(sub_tree.level) + 1)) level ";
                    sql += " FROM t_nested_category node,";
                    sql += " t_nested_category parent,";
                    sql += " t_nested_category sub_parent,";
                    sql += "(SELECT V.* ";
                    sql += " FROM (SELECT node.id, (COUNT(parent.name) - 1) level ";
                    sql += " FROM t_nested_category node, t_nested_category parent";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.id = @id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ) sub_tree";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt";
                    sql += " AND sub_parent.id = sub_tree.id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " and V.level <= 1";
                    sql += " and V.level > 0";
                    sql += " ORDER BY T.Lft";
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
        /// <summary>
        /// 返回节点的路径
        /// </summary>
        /// <param name="NodeName">当前节点名称</param>
        /// <returns></returns>
        public DataTable NodePath(string NodeName)
        {
            DataTable dt = null;
            try
            {
                string sql = "SELECT node.id,parent.Name FROM t_nested_category node  CROSS JOIN t_nested_category parent WHERE (node.lft BETWEEN parent.lft AND parent.rgt) AND (node.name = @name) ORDER BY node.id,parent.lft";
                SqlParameter[] parameter = new SqlParameter[1];
                parameter[0] = new SqlParameter("name", NodeName);
                dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
 
        /// <summary>
        /// 返回节点的ID
        /// </summary>
        /// <param name="nodeName">节点名称</param>
        /// <param name="nodePath">节点路径</param>
        /// <returns>返回-1,指示表中不存在当前节点名称</returns>
        public int NodeID(string nodeName, string nodePath)
        {
            int nodeID = -1;
            DataTable dt = NodePath(nodeName);
            if (dt != null)
            {
                string path = "";
                int id = -1;
                foreach (DataRow row in dt.Rows)
                {
                    string node = row[1].ToString ();
                    int tempid = Convert.ToInt32(row[0]);
                    if (id != tempid)
                    {
                        path = "\\" + node;
                        id = tempid;
                    }
                    else
                    {
                        path = path + "\\" + node;
                      
                    }
                    if (path.Equals(nodePath))
                    {
                        nodeID = Convert.ToInt32(row[0]);
                        break;
                    }
                }
            }
            return nodeID;
        }
        /// <summary>
        /// 返回根节点id
        /// </summary>
        /// <returns></returns>
        public int NodeRootID()
        {
            int nodeID = -1;
            try
            {
                string sql = "SELECT node.id,parent.Name FROM t_nested_category node CROSS JOIN t_nested_category parent WHERE (node.lft BETWEEN parent.lft AND parent.rgt) AND (node.type = @type) ORDER BY node.lft";
                SqlParameter[] parameter = new SqlParameter[1];
                parameter[0] = new SqlParameter("type", SqlDbType.Int);
                parameter[0].Value = (int)LeafNodeType.Root;
                SqlDataReader reader = MSQLHelper.ExecuteReader(CommandType.Text, sql, parameter);
                if (reader.Read())
                {
                    nodeID = reader.GetInt32(0);
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
         
            return nodeID;
        }
        /// <summary>
        /// 返回所有的叶子节点
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public System.Data.DataTable GetAllLeaf(params object[] list)
        {
            DataTable dt = null;
            try
            {
                string sql = "SELECT * FROM t_nested_category WHERE rgt = lft + 1 andtype=@type";
                if (list != null)
                {
                    SqlParameter[] parameter = new SqlParameter[list.Count ()];
                    for (int i = 0; i < list.Count(); i++)
                    {
                        parameter[i] = new SqlParameter("type", list[i]);
                    }
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        } /// <summary>
        /// 更新节点信息
        /// </summary>
        /// <param name="currentNodeName">当前节点名称</param>
        /// <param name="currentNodePath">当前节点路径</param>
        /// <param name="nodeInfo">更新的节点信息</param>
        /// <returns></returns>
        public bool ModifyNode(string currentNodeName, string currentNodePath, TreeNodeInfo nodeInfo)
        {
            bool successed = false;
            SqlConnection conn = null;
            SqlTransaction tran = null;
            try
            {
                int id = NodeID(currentNodeName, currentNodePath);
                DataTable dt = SubTree(currentNodeName, currentNodePath);
                conn = new SqlConnection(MSQLHelper.CONN_STRING);
                conn.Open();
                tran = conn.BeginTransaction();
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = conn;
                cmd.Transaction = tran;
                cmd.Parameters.Add(new SqlParameter("name", SqlDbType.NVarChar));
                cmd.Parameters["name"].Value = nodeInfo.NodeName;
                cmd.Parameters.Add(new SqlParameter("parent", SqlDbType.NVarChar));
                cmd.Parameters["parent"].Value = nodeInfo.ParentName;
                cmd.Parameters.Add(new SqlParameter("type", SqlDbType.Int));
                cmd.Parameters["type"].Value = nodeInfo.LeafType;
                cmd.Parameters.Add(new SqlParameter("paramkey", SqlDbType.NVarChar));
                cmd.Parameters["paramkey"].Value = nodeInfo.ParamKey;
                cmd.Parameters.Add(new SqlParameter("id", SqlDbType.Int));
                cmd.Parameters["id"].Value = id;
                cmd.Parameters.Add(new SqlParameter("unit", SqlDbType.NVarChar));
                cmd.Parameters["unit"].Value = nodeInfo.Unit;
                cmd.CommandText = "update  t_nested_category  set name=@name,parent=@parent,type=@type,paramkey=@paramkey,unit=@unit where id=@id";
                int n = cmd.ExecuteNonQuery();
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    TreeNodeInfo nodeInfo2 = new TreeNodeInfo();
                    nodeInfo2.ID = Convert.ToInt32(dt.Rows[i]["id"]);
                    nodeInfo2.ParentName = nodeInfo.NodeName;
                    //参数赋值
                    cmd.Parameters["parent"].Value = nodeInfo2.ParentName;
                    cmd.Parameters["id"].Value = nodeInfo2.ID;
                    cmd.CommandText = "update t_nested_category set parent=@parent where id=@id";
                    n = cmd.ExecuteNonQuery();
                }
                if (n > 1)
                {
                    successed = true;
                }
                tran.Commit();
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                tran.Rollback();
                throw ex;
            }
            finally
            {
                if (conn != null)
                {
                    conn.Close();
                    tran.Dispose();
                    conn.Dispose();
                }
            }
            return successed;
        }
        /// <summary>
        /// 返回节点名称的树
        /// </summary>
        /// <param name="NodeName">节点名称</param>
        /// <param name="NodePath">当前节点路径</param>
        /// <returns></returns>
        public DataTable FullTreeByNodeName(string NodeName, string NodePath)
        {
            DataTable dt = null;
            try
            {
                int id = NodeID(NodeName, NodePath);
                if(id > -1)
                {
                    string sql = "SELECT T.*,V.level";
                    sql += " FROM (SELECT node.id,";
                    sql += "(COUNT(parent.name) - (AVG(sub_tree.level) + 1)) level ";
                    sql += " FROM t_nested_category node,";
                    sql += " t_nested_category parent,";
                    sql += " t_nested_category sub_parent,";
                    sql += "(SELECT V.* ";
                    sql += " FROM (SELECT node.id, (COUNT(parent.name) - 1) level ";
                    sql += " FROM t_nested_category node, t_nested_category parent";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.id = @id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ) sub_tree";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt";
                    sql += " AND sub_parent.id = sub_tree.id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ORDER BY T.Lft";
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
        /// <summary>
        /// 获得根节点开始的树
        /// </summary>
        /// <returns></returns>
        public DataTable FullTree()
        {
            DataTable dt = null;
            try
            {
                int id = NodeRootID();
                if (id > -1)
                {
                    string sql = "SELECT T.*,V.level";
                    sql += " FROM (SELECT node.id,";
                    sql += "(COUNT(parent.name) - (AVG(sub_tree.level) + 1)) level ";
                    sql += " FROM t_nested_category node,";
                    sql += " t_nested_category parent,";
                    sql += " t_nested_category sub_parent,";
                    sql += "(SELECT V.* ";
                    sql += " FROM (SELECT node.id, (COUNT(parent.name) - 1) level ";
                    sql += " FROM t_nested_category node, t_nested_category parent";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.id = @id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ) sub_tree";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt";
                    sql += " AND sub_parent.id = sub_tree.id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ORDER BY T.Lft";
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
        /// <summary>
        /// 返回当前节点子树
        /// </summary>
        /// <param name="NodeName">当前节点名称</param>
        /// <param name="NodePath">当前节点路径</param>
        /// <returns></returns>
        public DataTable SubTree(string NodeName, string NodePath)
        {
            DataTable dt = null;
            try
            {
                int id = NodeID(NodeName, NodePath);
                if (id > -1)
                {
                    string sql = "SELECT T.*,V.level";
                    sql += " FROM (SELECT node.id,";
                    sql += "(COUNT(parent.name) - (AVG(sub_tree.level) + 1)) level ";
                    sql += " FROM t_nested_category node,";
                    sql += " t_nested_category parent,";
                    sql += " t_nested_category sub_parent,";
                    sql += "(SELECT V.* ";
                    sql += " FROM (SELECT node.id, (COUNT(parent.name) - 1) level ";
                    sql += " FROM t_nested_category node, t_nested_category parent";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.id = @id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " ) sub_tree";
                    sql += " WHERE node.lft BETWEEN parent.lft AND parent.rgt";
                    sql += " AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt";
                    sql += " AND sub_parent.id = sub_tree.id";
                    sql += " GROUP BY node.id) V,";
                    sql += " t_nested_category T";
                    sql += " WHERE V.id = T.id";
                    sql += " and V.level <= 1";
                    sql += " and V.level > 0";
                    sql += " ORDER BY T.Lft";
                    SqlParameter[] parameter = new SqlParameter[1];
                    parameter[0] = new SqlParameter("id", id);
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
        /// <summary>
        /// 返回节点的路径
        /// </summary>
        /// <param name="NodeName">当前节点名称</param>
        /// <returns></returns>
        public DataTable NodePath(string NodeName)
        {
            DataTable dt = null;
            try
            {
                string sql = "SELECT node.id,parent.Name FROM t_nested_category node  CROSS JOIN t_nested_category parent WHERE (node.lft BETWEEN parent.lft AND parent.rgt) AND (node.name = @name) ORDER BY node.id,parent.lft";
                SqlParameter[] parameter = new SqlParameter[1];
                parameter[0] = new SqlParameter("name", NodeName);
                dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }
 
        /// <summary>
        /// 返回节点的ID
        /// </summary>
        /// <param name="nodeName">节点名称</param>
        /// <param name="nodePath">节点路径</param>
        /// <returns>返回-1,指示表中不存在当前节点名称</returns>
        public int NodeID(string nodeName, string nodePath)
        {
            int nodeID = -1;
            DataTable dt = NodePath(nodeName);
            if (dt != null)
            {
                string path = "";
                int id = -1;
                foreach (DataRow row in dt.Rows)
                {
                    string node = row[1].ToString ();
                    int tempid = Convert.ToInt32(row[0]);
                    if (id != tempid)
                    {
                        path = "\\" + node;
                        id = tempid;
                    }
                    else
                    {
                        path = path + "\\" + node;
                      
                    }
                    if (path.Equals(nodePath))
                    {
                        nodeID = Convert.ToInt32(row[0]);
                        break;
                    }
                }
            }
            return nodeID;
        }
        /// <summary>
        /// 返回根节点id
        /// </summary>
        /// <returns></returns>
        public int NodeRootID()
        {
            int nodeID = -1;
            try
            {
                string sql = "SELECT node.id,parent.Name FROM t_nested_category node CROSS JOIN t_nested_category parent WHERE (node.lft BETWEEN parent.lft AND parent.rgt) AND (node.type = @type) ORDER BY node.lft";
                SqlParameter[] parameter = new SqlParameter[1];
                parameter[0] = new SqlParameter("type", SqlDbType.Int);
                parameter[0].Value = (int)LeafNodeType.Root;
                SqlDataReader reader = MSQLHelper.ExecuteReader(CommandType.Text, sql, parameter);
                if (reader.Read())
                {
                    nodeID = reader.GetInt32(0);
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
         
            return nodeID;
        }
        /// <summary>
        /// 返回所有的叶子节点
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public System.Data.DataTable GetAllLeaf(params object[] list)
        {
            DataTable dt = null;
            try
            {
                string sql = "SELECT * FROM t_nested_category WHERE rgt = lft + 1 andtype=@type";
                if (list != null)
                {
                    SqlParameter[] parameter = new SqlParameter[list.Count ()];
                    for (int i = 0; i < list.Count(); i++)
                    {
                        parameter[i] = new SqlParameter("type", list[i]);
                    }
                    dt = MSQLHelper.getDS(CommandType.Text, sql, parameter).Tables[0];
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return dt;
        }

猜你喜欢

转载自blog.csdn.net/lishiming0308/article/details/8141197
今日推荐