将Hierarchical DataTable转换为Json

时间:2015-02-13 09:03:23

标签: json linq datatable nested-lists sublist

我有一个如下的分层数据表,它生成菜单及其子菜单。主菜单的parentId为0.子菜单有父ID引用parentId。



ResourceId   DisplayName   ParentId     Url
-----------------------------------------------
1           Home           0            Some Url
2           Student        0            Some Url
3           Staff          0            Some Url
4           Library        0            Some Url
6           StudentAtt     1            Some Url
7           TimeTable      1            Some Url
8           Staff Att      2            Some Url
9           Book Issue     3            Some Url
10          Book Return    3            Some Url
11          Fee Payment    4            Some Url
12          Book fine      10           Some Url




需要将其转换为Json。下面是我试过的代码。我试图检查SubMenu的ParentId是否等于主菜单的ResourceId。但是不显示subMenu。 (变量表是DataTable)



var rows = table.Rows.Cast<DataRow>().ToList();
            var result = rows.Where(x => x["ParentId"].ToString() == "0").GroupBy(r => new { x = r["ResourceId"] }).Select(
                g => new
                {
                    //MenuLevel = g.Key.x,
                    MenuDetails = g.GroupBy(r => new {a = r["DisplayName"], b = r["Url"]}).Select(
                        detail => new
                        {
                            DisplayName = detail.Key.a,
                            Url = detail.Key.b,
                            SubMenu =
                                detail.Where(y => g.Key.x.ToString()==y["ParentId"].ToString()).
                                    GroupBy(r => new {f = r["DisplayName"]}).Select(
                                    subMenu=>new
                                    {
                                        SubMenuDisplayName=subMenu.Key.f
                                    }
                                    )
                        }
                        )
                });
&#13;
&#13;
&#13;

我得到的结果如下。

[{"MenuDetails":[{"DisplayName":"Home","Url":null,"SubMenu":[]}]},{"MenuDetails":[{"DisplayName":"Student","Url":null,"SubMenu":[]}]},{"MenuDetails":[{"DisplayName":"Staff","Url":null,"SubMenu":[]}]},{"MenuDetails":[{"DisplayName":"Library","Url":null,"SubMenu":[]}]}]

但预期结果是:

[{"MenuDetails":[{"DisplayName":"Home","Url":null,"SubMenu":[{"SubMenuDisplayName":"StudentAtt"},{"SubMenuDisplayName":"TimeTable"}]}]},{"MenuDetails":[{"DisplayName":"Student","Url":null,"SubMenu":[{"SubMenuDisplayName":"Staff Att"}]}]},{"MenuDetails":[{"DisplayName":"Staff","Url":null,"SubMenu":[{"SubMenuDisplayName":"Book Issue"},{"SubMenuDisplayName":"Book Return"}]}]},{"MenuDetails":[{"DisplayName":"Library","Url":null,"SubMenu":[{"SubMenuDisplayName":"Fee Payment "}]}]}]

我还需要显示子子菜单(其父ID指向子菜单的资源ID)任何一个请帮助

1 个答案:

答案 0 :(得分:0)

您的问题在

SubMenu = detail.Where(y => ...

,详细信息已经过滤到rows.Where(x => x["ParentId"].ToString() == "0"),因此它不包含子项。

这将更接近你想要的但只返回前两个级别。

var result = rows.Where(x => x["ParentId"].ToString() == "0").GroupBy(r => new { x = r["ResourceId"] }).Select(
    g => new {
        //MenuLevel = g.Key.x,
        MenuDetails = g.GroupBy(r => new { a = r["DisplayName"], b = r["Url"] }).Select(
            detail => new {
                DisplayName = detail.Key.a,
                Url = detail.Key.b,
                SubMenu =
                    rows.Where(y => g.Key.x.ToString() == y["ParentId"].ToString()).
                        GroupBy(r => new { f = r["DisplayName"] }).Select(
                        subMenu => new {
                            SubMenuDisplayName = subMenu.Key.f
                        }
                        )
            }
            )
    });

要创建完整的层次结构,您需要为每个菜单项创建对象,然后将它们连接在一起。如果您创建一个表示菜单项的类型,则会更容易,例如:

public class MenuDeatils {

    public int ID;
    public string Url;
    public string DisplayName;
    public IEnumerable<MenuDeatils> SubMenu;

}

然后,您可以为每个项目创建一个对象,并按其ParentIds对其进行分组:

var groups = (from row in rows
              group row by row["ParentId"] into parentGroup
              select new {
                Key = (int)parentGroup.Key,
                Items = parentGroup.Select(r => new MenuDeatils {
                    ID = (int)r["ResourceId"],
                    DisplayName = (string)r["DisplayName"],
                    Url = (string)r["Url"]
                })
              }).ToList();

注意:这里列举了查询(.ToList()),因此我们创建了一组MenuDeatils对象。

接下来,我们可以从我们创建的组中设置每个MenuDetails对象的SubMenu属性。

foreach (var menuItem in groups.SelectMany(g => g.Items)) {
    var submenu = groups.SingleOrDefault(g => g.Key == menuItem.ID);
    if (submenu != null) {
        menuItem.SubMenu = submenu.Items;
    }
};

可以在以下位置找到顶级项目:

var result = groups.Single(g => g.Key == 0).Items

,现在已附上所有后代菜单。