在Portal Starter Kit中,用嵌套DataList实现了如上图所示的问题及答复列表,感觉不错,一种实现思路。特将该实现思路摘取出来,当然其中也存在一些小问题,不过基本上还是不错的。
1.数据表的设计
在该实现中,只设计了一张表Portal_discussion。在一般的类似功能的实现中,一般是两种表:一个表存放的是顶层问题描述表,另一个存放的是问题的回复。但在Portal Starter中,只设计了Portal_discussion一个表,在该表中同时存放了问题以及问题的回复。表结构如下图所示。
其中,ItemID为自增列;ModuleID为模块ID。其最重要应用的是字段DisplayOrder,我们可以发现
该字段是nvarchar(750),从字段的英文名字上,我们可以将其翻译为“显示顺序”。那么用该字段是怎么实现的显示顺序的呢?其实,在该字段中存放的是该问题上层问题的DisplayOrder值+本次发表问题的时间,所形成的新的字符串值(日期),如下图所示。
2.DataList
该功能的实现主要利用了嵌套DataList来实现的。代码如下:
0 1 < asp:datalist id ="TopLevelList" runat ="server" DataKeyField ="Parent" ItemStyle-Cssclass ="Normal" width ="98%" > 0 2 < ItemTemplate > 0 3 < asp:ImageButton id ="btnSelect" ImageUrl='<%# NodeImage((int)DataBinder.Eval(Container.DataItem, "ChildCount")) % >' CommandName="select" runat="server" /> 0 4 < asp:hyperlink Text='<%# DataBinder.Eval(Container.DataItem, "Title") % >' NavigateUrl=' < %# FormatUrl((int)DataBinder.Eval(Container.DataItem, "ItemID")) % >' Target="_new" runat="server" ID="Hyperlink1" />, 0 5 from 0 6 < %# DataBinder.Eval(Container.DataItem,"CreatedByUser") % > 0 7 , posted 0 8 < %# DataBinder.Eval(Container.DataItem,"CreatedDate", "{0:g}") % > 0 9 </ItemTemplate> 10 < SelectedItemTemplate > 11 < asp:ImageButton id ="btnCollapse" ImageUrl ="~/images/minus.gif" runat ="server" CommandName ="collapse" /> 12 < asp:hyperlink Text='<%# DataBinder.Eval(Container.DataItem, "Title") % >' NavigateUrl=' < %# FormatUrl((int)DataBinder.Eval(Container.DataItem, "ItemID")) % >' Target="_new" runat="server" ID="Hyperlink2" />, 13 from 14 < %# DataBinder.Eval(Container.DataItem,"CreatedByUser") % > 15 , posted 16 < %# DataBinder.Eval(Container.DataItem,"CreatedDate", "{0:g}") % > 17 < asp:DataList id ="DetailList" ItemStyle-Cssclass ="Normal" datasource="<%# GetThreadMessages() % >" runat="server"> 18 < ItemTemplate > 19 < %# DataBinder.Eval(Container.DataItem, "Indent") % > 20 < img src="<%=Global.GetApplicationPath(Request)% >/images/1x1.gif" height="15"> 21 < asp:hyperlink Text='<%# DataBinder.Eval(Container.DataItem, "Title") % >' NavigateUrl=' < %# FormatUrl((int)DataBinder.Eval(Container.DataItem, "ItemID")) % >' Target="_new" runat="server" ID="Hyperlink3" />, 22 from 23 < %# DataBinder.Eval(Container.DataItem,"CreatedByUser") % > 24 , posted 25 < %# DataBinder.Eval(Container.DataItem,"CreatedDate", "{0:g}") % > 26 </ItemTemplate> 27 </asp:DataList> 28 </SelectedItemTemplate> 29 </asp:datalist>3.三个重要的SQL存储过程
1.增加一个问题。不管增加的是顶层问题或是对某个问题的回复问题,都可以利用该存储过程。
0 1 CREATE PROCEDURE Portal_AddMessage 0 2 ( 0 3 @ItemID int OUTPUT , 0 4 @Title nvarchar (100 ) , 0 5 @Body nvarchar (3000 ) , 0 6 @ParentID int , 0 7 @UserName nvarchar (100 ) , 0 8 @ModuleID int 0 9 ) 10 11 AS 12 / * Find DisplayOrder of parent item * / 13 DECLARE @ParentDisplayOrder as nvarchar (750 ) 14 SET @ParentDisplayOrder = "" 15 16 SELECT 17 @ParentDisplayOrder = DisplayOrder 18 FROM Portal_Discussion 19 WHERE 20 ItemID = @ParentID 21 22 INSERT INTO Portal_Discussion 23 ( 24 Title , 25 Body , 26 DisplayOrder , 27 CreatedDate , 28 CreatedByUser , 29 ModuleID 30 ) 31 32 VALUES 33 ( 34 @Title , 35 @Body , 36 @ParentDisplayOrder + CONVERT ( nvarchar (24 ) , GetDate ( ) , 21 ) , 37 GetDate ( ) , 38 @UserName , 39 @ModuleID 40 ) 41 42 SELECT 43 @ItemID = @@Identity 44 45 GO【说明】该存储过程中,对于参数@ParentID的值,如果是新增的问题,@ParentID=0;如果是回复某个问题的,那么@ParentID=那个问题的ItemID。该存储过程的实现思路是:
(1)声明一个@ParentDisplayOrder as nvarchar(750)
(2)根据@ParentID的值来,查找父问题的DisplayOrder字段的值,并存储到@ParentDisplayOrder变量中
(3)向表中插入数据。其中的关键是在DisplayOrder字段的赋值时,@ParentDisplayOrder + CONVERT( nvarchar(24), GetDate(), 21 )。其中CONVERT是用来将GetDate()获得日期做了格式化,会返回类似如下值:2009-01-22 23:16:09.807(长度为23,下面的获取顶层问题列表的存储过程会用到)。
(4)最后将新增加的问题的ItemID返回。
SELECT @ItemID = @@Identity2.获取顶层问题列表;
0 1 CREATE PROCEDURE Portal_GetTopLevelMessages 0 2 ( 0 3 @ModuleID int 0 4 ) 0 5 AS 0 6 0 7 SELECT 0 8 ItemID , 0 9 DisplayOrder , 10 LEFT (DisplayOrder , 23 ) AS Parent , 11 ( SELECT COUNT ( * ) -1 FROM Portal_Discussion Disc2 WHERE LEFT (Disc2 .DisplayOrder , LEN ( RTRIM (Disc .DisplayOrder ) ) ) = Disc .DisplayOrder ) AS ChildCount , 12 Title , 13 CreatedByUser , 14 CreatedDate 15 16 FROM Portal_Discussion Disc 17 18 WHERE 19 ModuleID =@ModuleID 20 AND 21 ( LEN ( DisplayOrder ) / 23 ) = 1 22 23 ORDER BY 24 DisplayOrder 25 26 GO由于在该系统中,顶层问题,以及对顶层问题的回复都在一个表里,而在显示的时候,我们需要只显示顶层的问题列表,所以,该存储过程的主要目的是获取顶层问题列表。该存储过程的返回值,包括了顶层问题的基本信息,同时还包含了一个新的字段ChildCount,返回的是每个顶层问题的回复数量。用于控制在DataList中,图标的显示。回复数量>0的显示一个+号图标,没有回复数量的显示点图标。主要的是看明白这句:
11 ( SELECT COUNT ( * ) -1 FROM Portal_Discussion Disc2 WHERE LEFT (Disc2 .DisplayOrder , LEN ( RTRIM (Disc .DisplayOrder ) ) ) = Disc .DisplayOrder ) AS ChildCount ,3.获取某个指定问题。
该存储过程根据@ItemID参数,获取相应问题的信息。其中还包括了两个新字段信息。NextMessageID和PrevMessageID。
CREATE PROCEDURE Portal_GetSingleMessage ( @ItemID int ) AS DECLARE @nextMessageID int EXECUTE Portal_GetNextMessageID @ItemID , @nextMessageID OUTPUT DECLARE @prevMessageID int EXECUTE Portal_GetPrevMessageID @ItemID , @prevMessageID OUTPUT SELECT ItemID , ModuleID , Title , CreatedByUser , CreatedDate , Body , DisplayOrder , NextMessageID = @nextMessageID , PrevMessageID = @prevMessageID FROM Portal_Discussion WHERE ItemID = @ItemID其中获取NextMessageID(PreMessageID类似)的存储过程如下:
0 1 0 2 CREATE PROCEDURE Portal_GetNextMessageID 0 3 ( 0 4 @ItemID int , 0 5 @NextID int OUTPUT 0 6 ) 0 7 AS 0 8 0 9 DECLARE @CurrentDisplayOrder as nvarchar (750 ) 10 DECLARE @CurrentModule as int 11 12 / * Find DisplayOrder of current item * / 13 SELECT 14 @CurrentDisplayOrder = DisplayOrder , 15 @CurrentModule = ModuleID 16 FROM Portal_Discussion 17 WHERE 18 ItemID = @ItemID 19 20 / * Get the next message in the same module * / 21 SELECT Top 1 22 @NextID = ItemID 23 24 FROM Portal_Discussion 25 26 WHERE 27 DisplayOrder > @CurrentDisplayOrder 28 AND 29 ModuleID = @CurrentModule 30 31 ORDER BY 32 DisplayOrder ASC 33 34 / * end of this thread? * / 35 IF @@Rowcount < 1 36 SET @NextID = null 37 38 GO
其他细节,请看源代码吧。困了,睡觉了。
转载于:https://www.cnblogs.com/lzm525/archive/2009/01/22/1380123.html
