Проблема при создании меню, управляемого данными в asp.net

Я создаю управляемое данными динамическое меню в 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:

База данных меню

2 ответа

Решение

Решение, которое я нашел полезным для этой проблемы, было найдено на

Получение пунктов меню из базы данных в asp.net

И вот мой исходный код: -

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

{SqlConnection conn; protected void Page_Load (отправитель объекта, EventArgs e) {if (! IsPostBack) {getMenu (); }}

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

}

Попробуем угадать здесь и сказать, что это связано с порядком создания дочерних элементов 3-го уровня.

Вы явно добавляете родительские элементы в меню из коллекции rowParent, затем добавляете "остальные". Проблема в том, что когда вы запускаете 2-й цикл 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

Если сначала добавлено управление, то приложение Initiate будет работать, так как FindItem() найдет родительский элемент для добавления.

Тем не менее, если сначала инициируется Application, а управление еще не добавлено, оно выдаст ошибку, так как FindItem() завершится ошибкой (элемент еще не добавлен).

Вы можете добавить порядок по предложению и порядок по идентификатору родителя, чтобы обеспечить добавление элементов в таком порядке, чтобы родительские элементы с меньшим номером были добавлены первыми.

Или вы можете создать функцию и несколько раз передать ей родительский идентификатор для каждого уровня, чтобы всегда добавлять дочерние элементы к уже добавленным родителям. На iPad сейчас, но скоро добавлю немного кода.

Другие вопросы по тегам