【问题标题】:Database design for Magazine website with flexible horizontal menus具有灵活水平菜单的杂志网站数据库设计
【发布时间】:2012-10-06 09:55:52
【问题描述】:

我需要设计一个基于 CMS 的网站,使用 asp.net 网络表单 (c#) 和 MS SQL Server 作为杂志网站的后端数据库,该杂志网站每周都会发行。

样本数据

MagazinePages Table
PageID  PageName    LangID  PagePositionNo  PageURL     PageInheritance //PageID 
1           Home        1         10        Default.aspx    0
2           About Us    1         20        Page.aspx       0
3           PageOne     1         10        Page.aspx       2
4           PageTwo     1         20        Page.aspx       2
5           Media           1         30        Page.aspx       0
6           Video       1         10        Videos.aspx     5
8           News        1         40        News.aspx        0
9           Archive     1         50        #               0
10          Publication 1         60        Page.aspx       0
11          SpanishHome 2         10        Default.aspx        0
12          SpanisAboutUs 2       20        Page.aspx   0
------------------------------------------------------------------------------
Magazine
MagazineID  MagazineIssueCode   LangID  MagazineTitle   MagazineLiveIssue(CurrentIssue)
1       1           1   Mag Title       0
2       2           1   Mag Title       1
3       1           2   SpanisgMag Title    0
4       2           2   Mag Title       1
------------------------------------------------------------------------------

News Table
NewsID  NewsTitle   NewsCatID   MagazineID  Language    
1   News one    100     1       1
2   News two    100     1       1
3   news three  200     1       1
4   News four   300     1       1
5   News Five   100     2       1
6   News Six    300     2       1
7   News seven  200     2       2
------------------------------------------------------------------------------

上述方法的问题是,只有当所有记录都在 MagazinePages 中时,我才能创建子菜单,基于上面的示例,我可以为“关于我们”和多媒体创建子菜单我该如何设计我的数据库,以便我可以从不同的表中提取数据,例如按类别(政治、文化...)的 新闻杂志 表中的问题(问题 101、问题 102、问题103....)

我打算为此使用 ASP 菜单控件,这可能不是很灵活,因为我将有超过 100 期杂志,我可以在 asp.net 中使用什么或哪个多列菜单

我的数据库可能有很多流程,我希望能得到这方面的帮助,以便我可以将这个数据库用于这个 CMS 系统。如有任何相关问题,请随时提出。

添加: 如果我需要从MagazinePages Table 中提取所有菜单名称,那么这很容易,但我被要求具有示例中所示的菜单结构。问题是我可以从MagazinePages 表中为AboutUsMultimedia 生成菜单,但我没有任何页面,如政治、经济、...问题 101、102、103.. 在这个表中信息存储在不同的表中,例如新闻表中的News CategoryMagazine 表中的问题。我宁愿改变我的表格设计并使其灵活地从单独的表格中读取菜单信息,但我不确定如何

新闻表未显示在此架构中。

我所做的是为 CMS 页面创建了 ps_Pages 表,例如 Home、Aboutus、Contact、MediaCentre .....

我将与杂志相关的页面(实际上是具有不同类别或标签的文章,如文化、政治、体育、人物......)存储在 art_Article 表中

【问题讨论】:

  • 在 MagazinePages 表中,是否需要在所有内容前加上“Page”?例如:PageURL....还有什么URL?只是一个Page 对吗? PageIsHomePage?这能不能简单点IsHomePage?
  • 我可以按照您的建议更改列名,URL 列将包含处理程序文件(如 News.aspx、Video.aspx、Gallery.aspx ....)
  • 我的问题是,如果我需要从其他表(例如杂志表中的问题)创建菜单,则数据库设计对于基于菜单的设计并不灵活
  • 从两个表中加入选择怎么样?执行 2 个查询,获取您需要的数据,将其转换为最适合您并将其填充到菜单中!不要期望找到适合您的内置查询。不要根据您在编程时遇到的问题更改您的设计!改为更改您的查询并进行调整。
  • @KnowledgeSeeker 你的问题解决了吗??????

标签: c# asp.net sql-server database-design aspmenu-control


【解决方案1】:

为什么不用一个页面来处理内容?

只需拨打Page.aspx?Issue=4&Page=4

然后在您的代码中,您知道这是第 4 个问题并且他们想要第 4 页,然后您可以在 Page.aspx(.vb 或 .cs)中包含代码,它会翻译该代码,然后决定布局。

例如

Page.aspx?Issue=4&Style=Article&Content=5

所以在代码中你可以去,好吧,这是第 4 期获取第 4 期的数据库条目,好吧,他们想要第 4 期的内容 ID 5,然后放入文章的样式。

这意味着您不必在数据库类型中添加额外的页面,您只需根据需要添加内容,生成访问内容的 URL 的项目只需要显示所有内容。

【讨论】:

  • 我没明白你的意思,我将如何创建问题菜单,如杂志表中的示例所示。如果所有内容都在一个表中,那么这很容易,但我还必须从其他表中创建子菜单
  • 要创建问题菜单,您将对所有标记为问题 4 内容的内容进行数据库选择,然后遍历该列表。像Page.aspx?Issue=4&Style= //Style Of Page Variable &Content= //ID of content ? 建立菜单列表
【解决方案2】:

我认为您需要重新评估您的数据库架构。 例如,我会有一个名为“ParentMenuItems”的表

此表将包括所有顶级菜单项(主页、关于我们、问题等),并包含子菜单的文本。 然后你需要有一个与你的父菜单项有关系的 ChildMenu 表。

ParentMenuItems:
==============================================================
ID       | LinkText      | LangID     | Other Properties
==============================================================
1        | Home.aspx     | 1          | blah blah blah
2        | AboutUs.aspx  | 2          | blah blah blah

然后,您可以有另一个名为“ChildMenuItems”的表,如下所示:

ChildMenuItems:
===============================================================
ID   | LinkText       | LangID |  ParentID  | Other Properties...
===============================================================
1    | PageOne.aspx   | 1      | 2          | blah blah blah
2    | PageTwo.aspx   | 2      | 2          | blah blah blah

代码可以这样工作:

SELECT * FROM ParentMenuItems - //SQL to get Items

然后,编写一些foreach代码来枚举SQL结果

foreach(var ParentMenuItem in ParentMenuItems)
{ 
    //Get ParentMenuItem ID, run SQL select on child menu items, Example:
    //SELECT * from ChildMenuItems where ParentID = ID.FROM.PARENT.RESULT
    // Now you have all the child menu items, foreach those and add to repeater control
}

我希望这会有所帮助。 如果您有任何问题,请告诉我。

提示:实体框架可以轻松完成这项工作。

【讨论】:

  • 我可以通过使用我当前的表结构来实现相同的目标,因为我有PageInheritance,它类似于您的ParentID。通过我的方法,我可以将子菜单嵌套到任何级别。我的问题是我必须从Magazine Table 创建子菜单,例如问题。
  • 感谢您的建议。我认为对于我的情况,最好从菜单中删除 Issue 并将其作为单独的下拉菜单,因为我在过去 10-15 年有超过 70 个问题。我将离开新闻菜单,因为我只需要为此创建 3 个项目并将它们链接到正确的页面或编写查询以获取与政治、经济、文化相关的文章。 & 很快。这将使我的生活变得轻松,因为我找不到适合我的方案的解决方案。谢谢大家
【解决方案3】:

我不确定我是否理解您的需求,但我假设您想为整个系统创建一个菜单,而不是为每本杂志创建一个菜单,对吧?

如果是这样,我认为您正在寻找错误的问题:问题不是数据库架构,而是您的菜单应该由 N 个没有预定义标准的不同表自动填充的概念。

我会创建一个菜单表 - 并使杂志页面和菜单成为两个不同的表:如果您正在创建一个类似 CMS 的系统,您可能会有一个页面,我可以在其中编辑类别、问题以及 - 为什么不 - 菜单条目,完全不同于任何其他表。

另外,我会创建一个“标签”系统,我的所有新闻和问题都可以被“标记”,而不是放在一个专有类别中。有可能同时谈论政治和文化的新闻。然后,您将使用 content.aspx?tag=politics,而不是将用户定向到许多不同的 pages.aspx。创建标签时,我可以选择将此标签添加到菜单表中,在“新闻”、“问题”等下方。类别和问题也是如此。

如果它不符合您的需求,您可以尝试这些选项 - 但除特定菜单条目表之外的所有其他解决方案都会在我的大脑中引发“警告,检测到未来问题”:

1 - 创建一个菜单表,这是一个存储过程,它通过遵循特定规则填充此表,然后在诸如“类别”之类的表上触发,该表将截断并调用存储过程,每次内容更改时都重写菜单(听起来像一个快速修复我)

2 - 将“submenu_table”、“submenu_field”、“submenu_condition”等添加到杂志页面并使用动态 sql 选择数据(类似于Set @SQL='Select '+ submenu_field + ' from '+ submenu_table + ' where ' + submenu_condition; Exec(@SQL))(另一个快速修复,繁重且可能很慢的查询)

(编辑:) 3 - 在 sql 2008 及更高版本中还有 hierachyId 字段 ([http://blogs.msdn.com/b/manisblog/archive/2007/08/17/sql-server-2008-hierarchyid.aspx])1

【讨论】:

    【解决方案4】:

    为菜单创建一个表格

    CREATE TABLE [dbo].[tblMenuMaster](
    [MenuID] [int] IDENTITY(1,1) NOT NULL,
    [MenuName] [varchar](100) NULL,
    [DisplayOrder] [int] NULL,
    PRIMARY KEY CLUSTERED 
    (
    [MenuID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    

    为子菜单创建另一个表

    CREATE TABLE [dbo].[tblSubMenuMaster](
    [SubMenuID] [int] IDENTITY(1,1) NOT NULL,
    [MenuID] [int] NULL,
    [SubMenuName] [varchar](100) NULL,
    [MainMenuDisplayOrder] [int] NULL,
    [DisplayOrder] [int] NULL,
    [SubMenuUrl] [varchar](500) NULL,
    [VisibleInMenu] [bit] NULL,
    PRIMARY KEY CLUSTERED 
    (
    [SubMenuID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    

    现在转到母版页.. HTML 代码是:

       <div class="menubar">
            <%--<ul class="tabs">--%>
            <asp:Literal ID="ltMenus" runat="server"></asp:Literal>
            <%--</ul>--%>
        </div>
    

    代码背后的代码是:

    private void GenerateMenus()
    {
        clsMenu obj = new clsMenu();
        System.Data.DataSet ds = new System.Data.DataSet();
        String PageName = "";
        PageName = Path.GetFileName(Page.AppRelativeVirtualPath);
        ds = obj.GetMenusByRole(GetRoleId(), PageName);
    
        StringBuilder sb = new StringBuilder("<ul class='tabs'>");
    
        foreach (System.Data.DataRow row in ds.Tables[0].Rows)
        {
            sb.Append(String.Format("<li class='{0}'><a rel='{1}' href='{1}' > {2} </a> ", Convert.ToString(row["css"]), ResolveUrl(Convert.ToString(row["PagePath"])), Convert.ToString(row["MenuName"])));
            //sb.Append(String.Format("<li '><a rel='{0}' href='{0}' > {1} </a> ", ResolveUrl(Convert.ToString(row["PagePath"])), Convert.ToString(row["MenuName"])));
    
            System.Data.DataTable t = CCMMUtility.GetFilterDataforIntColumn("MenuID", Convert.ToString(row["MenuID"]), ds.Tables[1]);
            if (t.Rows.Count > 0)
            {
                sb.Append("<ul>");
    
                for (int i = 0; i < t.Rows.Count; i++)
                {
                    sb.Append(String.Format("<li><a href='{0}' class='dir' style='cursor: pointer;'>{1}</a></li>", ResolveUrl(Convert.ToString(t.Rows[i]["PagePath"])), Convert.ToString(t.Rows[i]["PageAliasName"])));
                }
    
                sb.Append("</ul>");
            }
            sb.Append("</li>");
        }
    
        sb.Append("</ul>");
    
    
        ltMenus.Text = sb.ToString();
    
    }
    

    它需要存储过程来根据角色ID调用菜单的动态,如下所示

    CREATE PROCEDURE [dbo].[proc_GetMenusByRole]
    (
    @RoleId int,  
    @PageName varchar(100)
    )
    AS
    SET NOCOUNT ON;
    SELECT mm.MenuID, mm.MenuName,dbo.Extract_CssNameForMenuByMenuIDAndPageName(mm.MenuID, @PageName) as css
    ,dbo.proc_Extract_MenuPageByRoleIDAndMenuID(@RoleId, mm.MenuID)
    as PagePath , mm.DisplayOrder   FROM tblMenuMaster mm WHERE mm.MenuID IN (SELECT s.MenuID from tblSiteRolePermissions p INNER JOIN
    tblSitePages s ON p.fkSitePageId = s.pkSitePageId
    WHERE (p.fkRoleId = @RoleId and p.ViewOnly=1))   
    Union All   
    select 0 as menuid ,'Change Password' as MenuName,  
    case @pagename   
    when 'ChangePassword.aspx' then 'active'  
    else ''  
    end  as css,'~/User/ChangePassword.aspx' as PagePath, 10000 as Displayorder  
    ORDER BY DisplayOrder     
    SELECT s.MenuID, s.pkSitePageId, s.PageAliasName, s.SitePageName,s.pagepath from tblSiteRolePermissions p 
    INNER JOIN tblSitePages s ON p.fkSitePageId = s.pkSitePageId  WHERE (p.fkRoleId =@RoleId and p.ViewOnly=1) ORDER BY s.pkSitePageId  
    

    //新的sp从这里开始

    CREATE function [dbo].[Extract_CssNameForMenuByMenuIDAndPageName](@MenuID int, 
    PageName varchar(100))
    returns nvarchar(50)
    as begin      
    declare @result nvarchar(50) 
    set @result = ''    
    IF EXISTS (SELECT pkSitePageId FROM tblsitepages WHERE (MenuID = @MenuID) AND (UPPER(SitePageName) = @PageName)) 
     BEGIN    
      SET @result = 'active'    
     END    
    return @result    
    end  
    

    //另一个使用的sp是

    CREATE function [dbo].[proc_Extract_MenuPageByRoleIDAndMenuID]
    (@RoleId int, @MenuID int)
    returns nvarchar(500) 
    as begin          
    declare @result nvarchar(500)
    SELECT top 1 @result = s.pagepath FROM tblSitePages AS s INNER JOIN tblSiteRolePermissions AS p ON s.pkSitePageId = p.fkSitePageId
    WHERE (p.fkRoleId = @RoleId) AND (s.MenuID = @MenuID)  and p.ViewOnly=1
    ORDER BY s.pkSitePageId 
    return  @result
    end  
    

    这只是一种方法,你可以根据你的要求修改它............

    proc_Extract_MenuPageByRoleIDAndMenuID sp用于获取Page名称及其路径,

    Extract_CssNameForMenuByMenuIDAndPageName sp 用于设置 active 类为第一个 li 表示第一个菜单。 跳这会帮助你...... 它的工作代码..

    【讨论】:

    • 谢谢拉曼,我会研究一下,它是否也能处理n级菜单。以及你们的角色ID,我没有使用任何角色..
    • 是的..我已经告诉过你..它是我的一个项目中的一个工作示例...如果您想创建 n 级,那么只需为此创建另一个表并与之关联我们在上面做的方式......
    • 我很害怕这种方法,因为我看不到任何其他方法现在我必须在每次添加新杂志问题或新类别到新部分时创建一个新菜单条目。感谢您的帮助
    • 只需为它创建一个master ..您可以在这些表中插入/更新删除...
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 2011-04-05
    相关资源
    最近更新 更多