8

I need to design a CMS based website using asp.net web form (c#) and MS SQL Server as backend database for a magazine website which will have weekly issues.

Sample Data

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
------------------------------------------------------------------------------

Problem with above approach is that I can create sub menus only if all the records are in MagazinePages based on above example I can create sub menus for “About Us” & Multimedia how can I design my database so that I can pull data from different table such as news by category (Politics, Culture...) & Issue from Magazine Table (Issue 101, Issue 102, Issue 103....)

I am planning to use ASP Menu control for this which may not be very flexible, since I will have over 100 issue of magazine how or which multi column menu I can use with asp.net

My database may have many flows, I would appreciate help in this regard so that I can use this database for this CMS system . Please feel free to ask question if any regarding this.

Added: If I need to pull all the menu name from MagazinePages Table then it is easy but I have been asked to have a menu structure as shown in the example. Problem with this is I can generate menus for AboutUs & Multimedia from MagazinePages Table but I don't have any pages like Politics, Economic, ... Issue 101, 102, 103.. in this Table as that information is stored in different table like News Category in News Table & Issue in Magazine table. I would rather change my table design & make it flexible to read menu information from separate table but I am not sure how

News Table is not show in this Schema.

What I have done is that I have created ps_Pages Table for CMS Pages like, Home, Aboutus, Contact, MediaCentre .....

I store Pages related to Magazine (Which actually are article with different category or tags like culture, politics, sports, people ...) in art_Article table

Learning
  • 19,469
  • 39
  • 180
  • 373
  • In the MagazinePages table, is it necessary to prefix everything with "Page"? For instanse: `PageURL`....what else is going to have a `URL`? Just a `Page` right? `PageIsHomePage`? Can this not be simply `IsHomePage?` – Arran Oct 16 '12 at 10:16
  • I can change the column name as you suggested, URL column will have the Handler files (Like News.aspx, Video.aspx, Gallery.aspx ....) – Learning Oct 16 '12 at 10:19
  • My problem is database design is not flexible for menu based design if i need to create menu from other table such as Issue from Magazine Table – Learning Oct 16 '12 at 10:21
  • what about Joining selects from both tables? execute 2 queries, get the data you need, transform it to suit you best and populate it to the menu! don't expect to find a built in query that will suit you. DON'T change your design per issue you face while programming! change your query instead and adapt it. – Moslem Ben Dhaou Oct 25 '12 at 09:57

4 Answers4

4

Why not have a single page deal with the content?

Just call Page.aspx?Issue=4&Page=4

Then in your code you know it's the 4th Issue and they want Page 4, then you can have code in the Page.aspx (.vb or .cs) which translates that and then decides on the layout.

So E.g.

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

So in the code you could then go, Okay it's issue 4 get the database entries for Issue 4, okay they want Content ID 5 from Issue 4, then put in the style of an Article.

This means you don't have to add extra pages into the database type you can simply just add content as you wish and the item which generates the URLs to access the content just need to show all the content.

Ryan McDonough
  • 9,732
  • 3
  • 55
  • 76
  • I didnt get your point, how will i create Issue Menu as show in example from Magazine Table. If all is in one table then it is easy but i have to create sub menus from other tables also – Learning Oct 16 '12 at 10:47
  • Well to create the issue menu you'll do a database select on all content tagged as issue 4 content, then loop through that list. Building the menu list like Page.aspx?Issue=4&Style= //Style Of Page Variable &Content= //ID of content ? – Ryan McDonough Oct 16 '12 at 12:18
3

I think you need to re-evaluate your database schema. For example, I would have a table called "ParentMenuItems"

This table would include all Top Menu Items (Home, About Us, Issues, etc), and have the text for child menus. Then you need to have a ChildMenu table that has relations to your Parent Menu items.

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

Then, you could have another table called "ChildMenuItems" like this:

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

The code could work like this:

SELECT * FROM ParentMenuItems - //SQL to get Items

Then, write some foreach code to enumerate the SQL results

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
}

I hope this helps. Let me know if you have questions.

TIP: Entity Framework will make very light work of this.

bugnuker
  • 3,918
  • 7
  • 24
  • 31
  • I can achieve same by using my current table structure as i have `PageInheritance` which is similar to your `ParentID`. With my approach i can have nested sub-menus to any level. My problem is that is that i have to create sub-menu like issue from `Magazine` Table. – Learning Oct 23 '12 at 04:27
  • I appreciate your suggestion. I think for my scenario it is better to drop the `Issue` from the menu and have it as a separate drop-down menu as i have over 70 issue from past 10-15 years. I will leave the News menu as i only need to create 3 items items for that & link them to correct page or write query to get the articles related to politics, economics, culture. & so on. this will make my life easy as i could not find solution which will fit in for my scenario. Thanks everyone – Learning Oct 23 '12 at 04:31
2

Create a table for menu's

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 another table for sub menu's

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

Now go to master page .. HTML code is:

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

Code behind code is :

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();

}

it needs stored proc to call menu's dynamic according to Role id like below

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  

//new sp starts here

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  

// another sp used is

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  

Its just a way to do this you can modify this according to your requirement.........

proc_Extract_MenuPageByRoleIDAndMenuID sp is used to get Page name and its path,

Extract_CssNameForMenuByMenuIDAndPageName sp is used to set active class to the first li means first menu. Hop this will help you..... Its the working code..

Ram Singh
  • 6,664
  • 35
  • 100
  • 166
  • Thanks raman, I will look into it, Will it also handle n-level of menus. & what you men by roleId, i am not using any role.. – Learning Oct 23 '12 at 05:00
  • yes.. i have already told you .. its a working example in one of my project... if you want to create n-level then just create another table for that and relate in the same manner we are doing above.... – Ram Singh Oct 23 '12 at 05:05
  • I was afraid of this approach as i could not see any other way of doing it now i have to create a new menu entry each time when we add a new Magazine issue or new category to new section. Appreciate you help – Learning Oct 23 '12 at 05:07
  • just create a master for it .. from where you can insert/update delete in these tables... – Ram Singh Oct 23 '12 at 05:09
2

I'm not sure I understood what you need, but I'll assume you want to create a menu for the whole system, and not a menu for each magazine, right?

If so, I think you are looking to the wrong problem: The problem is not the database schema, but the concept that your menu should be automatically filled by N different tables that have no predefined standard.

I would create a menu table - and make magazinepages and menu two distinct tables: If you are creating an CMS-like system, you'll probably have a page where I can edit categories, issues and - why not - menu entries, completely apart from any other tables.

Also, I'd create a "tags" system, where all my news and issues could be "tagged" instead of put in a exclusive category. It would make possible to have a news that talks about politics and culture at the same time. Then, instead of directing user to lots of different pages.aspx, you'd use a content.aspx?tag=politics. When creating tag, I'd have the option to add this tag to menu table, under "news", "issues", etc. Same for category and issues.

If it doesn't fit your needs, you can try those options - but all other solutions than a specific table for menu entries trows a "warning, future problems detected" in my brain:

1 - create a menu table, a stored procedure that fills this table by following specific rules and then triggers on tables like "category" that would truncate and call the stored procedure, rewriting menu every time content changes (sounds like a quick fix to me)

2 - Add a "submenu_table", "submenu_field", "submenu_condition" etc to magazinepages and use dynamic sql to select data (something like Set @SQL='Select '+ submenu_field + ' from '+ submenu_table + ' where ' + submenu_condition; Exec(@SQL)) (another quick fix, heavy and probably slow query)

(edit:) 3 - there's also hierachyId field in sql 2008 and above ([http://blogs.msdn.com/b/manisblog/archive/2007/08/17/sql-server-2008-hierarchyid.aspx])1

Retired_User
  • 1,595
  • 11
  • 17