用C#获取无限多级分类的实现

所做的小项目中需要多级分类, 试着学习实现多级分类。由于对存储过程本身并不大熟悉,也不想借助于treeview,于是递归逻辑采用C#实现,配合数数据库完成了多级分类的获取方法。增加分类节点应该说是比较简单的,此文暂略。

数据库表:CategoryInfo

字段名           类型

ciID                  int                        //记录序号,自增量

ciName         nvarchar(20)       //分类名

ciParent           int                       //父分类序号

ciLayer              int                      //所处的层次

ciDescription     nvarchar(200)   //对分类的描述

获取子分类的存储过程

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"],
                            (int)reader["ciNum"],
                            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服务器与数据库服务器不位于同一台服务器上时,更会受网络影响。

posted @ 2009-04-18 11:53  X-Jonney  阅读(969)  评论(0编辑  收藏  举报