原理:
我们先把树按照水平方式摆开。从根节点开始(“Food”),然后他的左边写上1。然后按照树的顺序(从上到下)给“Fruit”的左边写上2。这样,你沿着树的边界走啊走(这就是“遍历”),然后同时在每个节点的左边和右边写上数字。最后,我们回到了根节点“Food”在右边写上18。下面是标上了数字的树,同时把遍历的顺序用箭头标出来了。
我们称这些数字为左值和右值(如,“站点”的左值是1,右值是16)。正如你所见,这些数字按时了每个节点之间的关系。因为“流量计”有3和6两个值,所以,它是有拥有1-16值的“站点”节点的后续。同样的,我们可以推断所有左值大于2并且右值小于9的节点,都是有2-9的“门站t” 节点的后续。这样,树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做“改进前序遍历树”算法。
数据库表结构设计如下:
解释一下每个字段的意思
id 唯一值,自动增长,主键
parent 当前节点父节点的名称
name 当前节点名
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;
}