如何将层次结构数据从DataTable转换为JSON



我有一个分层数据表,如下所示,它生成一个菜单及其子菜单。主菜单具有0ParentId。每个子菜单都有一个引用表中另一行的ResourceIdParentId

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。下面是我试用过的代码。我正在尝试检查子菜单的ParentId是否等于主菜单的ResourceId。但不显示子菜单。(变量tableDataTable。)

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

我得到的结果如下:

[
    {
        "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 "
                    }
                ]
            }
        ]
    }
]

我还需要显示子菜单(其ParentId指向子菜单的ResourceId)。

您在问题中发布的"预期"JSON不是一个完全递归的结构,因为它在不同级别之间不一致:子菜单项使用与顶部菜单项不同的显示名称属性,并且它们本身没有URL或子菜单集合。此外,我认为您的JSON比它需要的更复杂:您不需要插入的"MenuDetails"数组,它们总是只有一个元素。相反,我建议采用一种更简单的结构,如

[
    {
        "DisplayName" : "Top Menu 1",
        "Url" : "/Top1",
        "SubMenu" : 
        [
            {
                "DisplayName" : "SubMenu Item 1",
                "Url" : "/Top1/Sub1",
                "SubMenu" : 
                [
                   ...
                ]
            },
            {
                "DisplayName" : "SubMenu Item 2",
                "Url" : "/Top1/Sub2",
                "SubMenu" : 
                [
                   ...
                ]
            },
            ...
        ]
    },
    {
        "DisplayName" : "Top Menu 2",
        "Url" : "/Top2",
        "SubMenu" : 
        [
            ...
        ]
    },
    ...
]

请注意JSON在各个级别上是如何一致的:每个菜单项都有一个DisplayName、一个Url和一个SubMenu,这是一个(可能是空的)更多菜单项的列表。级别之间的一致性是递归结构的关键。

为了制作这个JSON,我们首先需要一个类来表示菜单项:

class MenuItem
{
    public MenuItem()
    {
        SubMenu = new List<MenuItem>();
    }
    [JsonIgnore]
    public int Id { get; set; }
    [JsonIgnore]
    public int ParentId { get; set; }
    public string DisplayName { get; set; }
    public string Url { get; set; }
    public List<MenuItem> SubMenu { get; set; }
}

下一步是将平面DataTable转换为层次结构。为此,我将首先从数据表中构建一个MenuItems的字典,由Id:键控

DataTable table = new DataTable();
table.Columns.Add("ResourceId", typeof(int));
table.Columns.Add("DisplayName", typeof(string));
table.Columns.Add("ParentId", typeof(int));
table.Columns.Add("Url", typeof(string));
table.Rows.Add(1, "Home", 0, "/Home");
table.Rows.Add(2, "Student", 0, "/Student");
table.Rows.Add(3, "Staff", 0, "/Staff");
table.Rows.Add(4, "Library", 0, "/Library");
table.Rows.Add(6, "StudentAtt", 2, "/Student/StudentAtt");
table.Rows.Add(7, "TimeTable", 1, "/Home/TimeTable");
table.Rows.Add(8, "Staff Att", 3, "/Staff/StaffAtt");
table.Rows.Add(9, "Book Issue", 4, "/Library/BookIssue");
table.Rows.Add(10, "Book Return", 4, "/Library/BookReturn");
table.Rows.Add(12, "Fee Payment", 11, "/Library/BookFine/FeePayment");
table.Rows.Add(11, "Book Fine", 4, "/Library/BookFine");
Dictionary<int, MenuItem> dict =
    table.Rows.Cast<DataRow>()
              .Select(r => new MenuItem
              {
                  Id = r.Field<int>("ResourceId"),
                  ParentId = r.Field<int>("ParentId"),
                  DisplayName = r.Field<string>("DisplayName"),
                  Url = r.Field<string>("Url")
              })
             .ToDictionary(m => m.Id);

然后循环遍历字典,对于每个菜单项,查找其父项并将该项添加到父项的子项中。如果某个项没有父项(其ParentId0),请将该项添加到根菜单项列表中。以这种方式构建层次结构只需要遍历字典一次。

List<MenuItem> rootMenu = new List<MenuItem>();
foreach (var kvp in dict)
{
    List<MenuItem> menu = rootMenu;
    MenuItem item = kvp.Value;
    if (item.ParentId > 0)
    {
        menu = dict[item.ParentId].SubMenu;
    }
    menu.Add(item);
}

现在我们有了层次结构,使用Json.Net对其进行序列化是很简单的。(请注意,MenuItem类中的[JsonIgnore]属性阻止将IdParentId值添加到Json中。)

string json = JsonConvert.SerializeObject(rootMenu, Formatting.Indented);
Console.WriteLine(json);

以下是由上述代码生成的最终JSON:

[
  {
    "DisplayName": "Home",
    "Url": "/Home",
    "SubMenu": [
      {
        "DisplayName": "TimeTable",
        "Url": "/Home/TimeTable",
        "SubMenu": []
      }
    ]
  },
  {
    "DisplayName": "Student",
    "Url": "/Student",
    "SubMenu": [
      {
        "DisplayName": "StudentAtt",
        "Url": "/Student/StudentAtt",
        "SubMenu": []
      }
    ]
  },
  {
    "DisplayName": "Staff",
    "Url": "/Staff",
    "SubMenu": [
      {
        "DisplayName": "Staff Att",
        "Url": "/Staff/StaffAtt",
        "SubMenu": []
      }
    ]
  },
  {
    "DisplayName": "Library",
    "Url": "/Library",
    "SubMenu": [
      {
        "DisplayName": "Book Issue",
        "Url": "/Library/BookIssue",
        "SubMenu": []
      },
      {
        "DisplayName": "Book Return",
        "Url": "/Library/BookReturn",
        "SubMenu": []
      },
      {
        "DisplayName": "Book Fine",
        "Url": "/Library/BookFine",
        "SubMenu": [
          {
            "DisplayName": "Fee Payment",
            "Url": "/Library/BookFine/FeePayment",
            "SubMenu": []
          }
        ]
      }
    ]
  }
]

相关内容

  • 没有找到相关文章

最新更新