所做的小項目中需要多級分類, 試著學習實現多級分類。由于對存儲過程本身并不大熟悉,也不想借助于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服務器與數據庫服務器不位于同一臺服務器上時,更會受網絡影響。
新聞熱點
疑難解答