当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > C# 无限级分类的实现

ASP.NET
asp.net Server.MapPath方法注意事项
asp.net下常用的加密算法MD5、SHA-1应用代码
几个 ASP.NET 小技巧
ASP.NET内置对象之Application对象
ASP.NET使用正则表达式屏蔽垃圾信息
asp.net“服务器应用程序不可用” 解决方法
asp.net Linq把数据导出到Excel的代码
asp.net ext treepanel 动态加载XML的实现方法
silverlight2.0Beta版TextBox输入中文解决方法
asp.net转出json格式客户端显示时间
asp.net下Linq To Sql注意事项小结
ASP.NET动态加载用户控件的实现方法
asp.net web大文件上传带进度条实例代码
asp.net DZ论坛中根据IP地址取得所在地的代码
向asp.Net进发 数据库连接操作
.net 上传文件前所未有的简单
asp.net gridview代码绑定
asp.net中List的使用方法
Asp.net(C#)实现验证码功能代码
asp.NET开发中正则表达式中BUG分析

ASP.NET 中的 C# 无限级分类的实现


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-13   浏览: 248 ::
收藏到网摘: n/a

采用存储过程实现递归逻辑,直接返回子分类列表的方式应该有更好的性能,尤其是Web服务器与数据库服务器不位于同一台服务器上时,更会受网络影响。 数据库表: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服务器与数据库服务器不位于同一台服务器上时,更会受网络影响。