C# 无限级分类的实现 |
本文标签:C#,无限多级分类 数据库表:CategoryInfo 字段名 类型 ciID int //记录序号,自增量 ciName nvarchar(20) //分类名 ciParent int //父分类序号 ciLayer int //所处的层次 ciDescription nvarchar(200) //对分类的描述 分类的类设计 public class CategoryInfo { private int ciID;//分类ID private string ciName;//分类名 private int ciParent;//分类的父分类ID private string ciDescription;//分类描述 private int ciLayer;//分类所属层次 //构造函数 public CategoryInfo() { } public CategoryInfo(int cID, string cName, int cParent, string cDescription, int cLayer) { this.ciID = cID; this.ciName = cName; this.ciParent = cParent; this.ciDescription = cDescription; this.ciLayer = cLayer; } //属性 public int CategoryID { get{ return ciID;} set { ciID = value;} } public string CategoryName { get{ return ciName;} set { ciName = value; } } public int CategoryParent { get{ return ciParent;} set { ciParent = value; } } public string CategoryDescription { get { return ciDescription; } set { ciDescription = value; } } public int CategoryLayer { get { return ciLayer; } set { ciLayer = value; } } } 获取子分类的存储过程 CREATE PROCEDURE [dbo].[category_getChild] @cName nvarchar(20) AS BEGIN DECLARE @tmpID int SELECT @tmpID=ciID FROM CategoryInfo WHERE RTRIM(ciName) = RTRIM(@cName) if(@tmpID IS NOT NULL) SELECT * FROM CategoryInfo WHERE ciParent = @tmpID ORDER BY ciLayer END 获取子分类的函数 public IList<CategoryInfo> GetChildCategories(IList<CategoryInfo> cInfos,string cName) { SqlConnection con = new SqlConnection(connectionString); SqlCommand cmd = new SqlCommand("category_getChild", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new SqlParameter(PARAM_CNAME, SqlDbType.NVarChar, 20)); cmd.Parameters[PARAM_CNAME].Value = cName; IList<string> tmpNames = new List<string>(); //临时存储获取的子 try { con.Open(); SqlDataReader reader = cmd.ExecuteReader(); if (reader.HasRows) { while (reader.Read()) { CategoryInfo cInfo = new CategoryInfo( (int)reader["ciID"], reader["ciName"].ToString(), (int)reader["ciParent"], reader["ciDescription"].ToString(), (int)reader["ciLayer"] ); string tmpName = reader["ciName"].ToString(); cInfos.Add(cInfo);//添加获取到的分类到cInfos tmpNames.Add(tmpName);//添加获取到的子分类名到tmpNames } } } catch { throw new ApplicationException("获取分类出错!"); } finally { con.Close(); } foreach(string c in tmpNames) { cInfos = GetChildCategories(cInfos,c); //递归运算 。继续获取子分类 } return cInfos; } 说明:在该函数中,tmpNames如果换成是IList<CategoryInfo>,即它添加的元素与cInfos是一样的时,如果要移除其中的一项,则cInfos中会同时移除一项 。因为CategoryInfo是类,是引用类型的,而非值类型 。所以tmpNames采用了string类型,以避免这个问题 。 对上面这个函数直接调用还稍嫌麻烦,上层程序还需要建立一个IList<CategoryInfo>对象,因此可以增加一个函数来调用上面的函数 。这样,上层程序只需要提供分类名,以及是否包含本级分类两个参数就可以了 。 //获取子分类,其中布尔参数表示是否包含本级分类 public IList<CategoryInfo> GetCategories( string cName, bool IsIncludeSelf) { IList<CategoryInfo> cInfos = new List<CategoryInfo>(); cInfos = GetChildCategories(cInfos, cName); if (IsIncludeSelf == true) { cInfos.Insert(0, GetByName(cName));//根据名字获取分类,这个很简单,本文略 。 } return cInfos; } 注意:采用这种方式时,WEB服务器获取子分类时要在数据库服务器之间有多次往返,降低了性能 。采用存储过程实现递归逻辑,直接返回子分类列表的方式应该有更好的性能,尤其是Web服务器与数据库服务器不位于同一台服务器上时,更会受网络影响 。 |