【问题标题】:Issue in creating a data driven menu in asp.net在 asp.net 中创建数据驱动菜单的问题
【发布时间】:2013-03-07 10:53:56
【问题描述】:

我正在 asp.net 中创建一个数据驱动的动态菜单,使用 sql server 2008 R2 作为我的数据库。第一级的父节点和子节点工作得很好。但是子节点下面有另一个子节点,应用程序产生异常。我的问题的c#代码如下:

public partial class LeaveManagementSystemMasterPage : System.Web.UI.MasterPage
{
SqlConnection conn;
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        getMenu();
    }
}

private void getMenu()
{
    Connect();
    conn.Open();
    DataSet ds = new DataSet();
    DataTable dt = new DataTable();
    string sqlQuery = "select * from menu";
    SqlDataAdapter da = new SqlDataAdapter(sqlQuery, conn);
    da.Fill(ds);
    dt = ds.Tables[0];
    DataRow[] rowParent = dt.Select("ParentID=" + 0);
    DataRow[] rowChild = dt.Select("ParentID>"+0);

    //populating the first level of the menu
    foreach (DataRow dr in rowParent)
    {
        Menu1.Items.Add(new MenuItem(dr["MenuName"].ToString(),dr["MenuID"].ToString(),"",""));
    }

    //populating the children in menu
    foreach (DataRow dr in rowChild)
    {
        MenuItem child = new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(), "", "");
        Menu1.FindItem(dr["ParentID"].ToString()).ChildItems.Add(child);

    }


    conn.Close();

}

public void Connect()
{
    string conStr="Data Source=HO-0000-LAP; Initial Catalog=LeaveManagementSystem; Integrated Security=true";
     conn = new SqlConnection(conStr);
}

}

这是我在 sqlserver 2008 中设计的表:-

【问题讨论】:

  • 我根据猜测添加了一个答案。如果您发布异常并显示您在哪一行得到异常,这将有所帮助。您可以查看变量并查看添加失败的项目,尽管您只有 1 个 3 级子项目 (ID 311),但很容易猜到。
  • 感谢大卫,提供您的信息,但我已经找到了解决方案,我已将其发布为我的答案。请参考。
  • 既然你的解决方案就是答案,你可以接受那个:)
  • 是的,我点击了好东西空心刻度线,但我无法将其标记为答案,因为我的声誉在 SO 中很低 :-( 但我可以在 2 天后这样做 :-)

标签: c# asp.net sql-server-2008 visual-studio-2008


【解决方案1】:

我发现对这个问题有用的解决方案在

Getting Menu Items from database in asp.net

这是我的源代码:-

public partial class LeaveManagementSystemMasterPage : System.Web.UI.MasterPage

{ SqlConnection 连接; protected void Page_Load(object sender, EventArgs e) { 如果(!IsPostBack) { 获取菜单(); } }

private void getMenu()
{
    Connect();
    DataSet ds = new DataSet();
    DataTable dt = new DataTable();
    string sqlQuery = "select * from menu";
    SqlDataAdapter da = new SqlDataAdapter(sqlQuery, conn);
    da.Fill(ds);
    dt = ds.Tables[0];
    AddTopMenuItems(dt);


}

private void AddTopMenuItems(DataTable menuData)
{
    DataView view = new DataView(menuData);
    view.RowFilter = "ParentID = 0";
    foreach (DataRowView rowView in view)
    {
        MenuItem topItem = new MenuItem(rowView["MenuName"].ToString(),rowView["MenuID"].ToString());
        Menu1.Items.Add(topItem);
        AddChildItems(menuData, topItem);
    }

}

private void AddChildItems(DataTable menuData, MenuItem parentMenuItem)
{
    DataView view = new DataView(menuData);
    view.RowFilter = "ParentID = " + parentMenuItem.Value;

    foreach(DataRowView rowView in view)
    {
        MenuItem childItem = new MenuItem(rowView["MenuName"].ToString(), rowView["MenuID"].ToString());
        parentMenuItem.ChildItems.Add(childItem);
        AddChildItems(menuData, childItem);
    }

}

public void Connect()
{
    string conStr="Data Source=HO-0000-LAP; Initial Catalog=LeaveManagementSystem; Integrated Security=true";
     conn = new SqlConnection(conStr);
}

}

【讨论】:

  • 但是,仍然存在一些兼容性问题,因为此代码在 google chrome 上不起作用,但在 windows 的 IE 8 中兼容。
  • 解决了forums.asp.net/p/1315088/2713325.aspx的chrome浏览器兼容性问题“cnobles”的帖子帮了我:-)
【解决方案2】:

在这里冒险猜测一下,说这与第三级子项的创建顺序有关。

您从 rowParent 集合显式地将父项添加到菜单,然后添加“其余”。问题是,当您开始第二个 for 循环以添加子项时,您依赖于项目的顺序,以便首先添加更高级别的项目。这不能保证。

那么可能发生的事情(如果您发布我们可以确认的异常)是这样的

在 foreach 循环(在 rowParent 上)之后,您的菜单对象添加了所有 5 个父项

Administration (ID 1), 
Setup (ID 2)
Operations (ID 3) 
Reports (ID 4) 
Logout (ID 5)

例如,在第 2 次 foreach 中,让您有 2 个项目,例如因为这很可能是您的问题所在

Management ID 31, ParentID 3
Initiate Application ID 311, ParentID 31

如果首先添加管理,则启动应用程序将作为 FindItem() 将找到要添加到的父项。

但是,如果先启动Application,并且还没有添加管理,则会抛出错误,因为FindItem()会失败(尚未添加项目)。

您可以添加 order by 子句和 order by Parent ID,以确保按顺序添加项目,以便首先添加编号较低的父项目。

或者您可以创建一个函数并为每个级别多次传递父 ID,以确保您始终将子项添加到已添加的父项。现在在 iPad 上,但很快会添加一些代码。

【讨论】:

  • 是的,我在调用 finditem() 的行中有错误,但我已通过使用链接 stackoverflow.com/questions/12349163/… 更改了我的代码
  • 好吧,答案看起来更复杂,但如果它有效,它就有效。这是一个简单的显示如何使用数据视图进行排序的简单示例,您可以按“ParentID ASC”进行排序,然后将所有项目添加到一个循环中:stackoverflow.com/questions/2294180/sort-items-in-datatable
  • 是的,大卫,通过在 DataView 中排序,排序非常简单。但是您不认为问题的本质是按升序排列值吗?我的问题是填充一个菜单,这需要我的数据库中的父 id 列分为两部分。一个用于 ParentID=0 的父元素,另一个大于 0
  • 是和否...在您的示例中,您说的项目 ParentID > 0,它们仍然有多个级别。 ID 为 311 的项目的 ParentID 为 31 - 如果该项目未首先添加到菜单中,则 FindItem() 会出现异常。在您的简单案例中进行排序是可行的。但是,您找到的解决方案更健壮,不依赖于排序,而是依赖于其上一级的 ID,这是正确的方法。在更复杂的情况下,这是一个递归问题,而不是排序问题。
  • 这就是我试图评论的内容,我的问题是递归,因为有两个或两个以上级别的子菜单。而且我发布的这段代码也适用于两个以上的级别,所以对 SO 的 karthik 竖起大拇指 :-) 他真的让我的生活变得轻松 :-) 并感谢 David 对此的真诚支持 :-)跨度>
猜你喜欢
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
相关资源
最近更新 更多