从结构化数据构建JSON层次结构

9

C# | .NET 4.5 | Entity Framework 5

我从 SQL 查询中获得的数据以 ID、ParentID 和 Name 的形式返回。我想将这些数据解析成分层的 JSON 字符串。迄今为止,这似乎是一个比应该更困难的任务。由于我使用了 Entity,数据作为 IEnumerable 很好地返回给我。现在我相信我只需要某种形式的递归,但我不太确定从哪里开始。任何帮助都会受到赞赏。

数据返回格式如下

id   parentId    name
1    1           TopLoc
2    1           Loc1
3    1           Loc2
4    2           Loc1A

代码如下

public static string GetJsonLocationHierarchy(long locationID)
{
    using (EntitiesSettings context = new EntitiesSettings())
    {
        // IEnumerable of ID,ParentID,Name
        context.GetLocationHierarchy(locationID);
    }
}

我希望最终的结果是这样的:

{
    "id": "1",
    "parentId": "1",
    "name": "TopLoc",
    "children": [
        {
            "id": "2",
            "parentId": "1",
            "name": "Loc1",
            "children": [
                {
                    "id": "4",
                    "parentId": "2",
                    "name": "Loc1A",
                    "children": [
                        {}
                    ]
                }
            ]
        },
        {
            "id": "3",
            "parentId": "1",
            "name": "Loc2",
            "children": [
                {}
            ]
        }
    ]
}
1个回答

12

将一个平面表转换为层次结构的一种方法是将所有节点放入一个字典中。然后迭代字典,对于每个节点,查找其父节点并将其添加到父节点的子节点中。从那里,您只需要找到根节点并将其序列化即可。

以下是演示该方法的示例程序:

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<Location> locations = new List<Location>
        {
            new Location { Id = 1, ParentId = 1, Name = "TopLoc" },
            new Location { Id = 2, ParentId = 1, Name = "Loc1" },
            new Location { Id = 3, ParentId = 1, Name = "Loc2" },
            new Location { Id = 4, ParentId = 2, Name = "Loc1A" },
        };

        Dictionary<int, Location> dict = locations.ToDictionary(loc => loc.Id);

        foreach (Location loc in dict.Values)
        {
            if (loc.ParentId != loc.Id)
            {
                Location parent = dict[loc.ParentId];
                parent.Children.Add(loc);
            }
        }

        Location root = dict.Values.First(loc => loc.ParentId == loc.Id);

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Formatting = Formatting.Indented
        };
        string json = JsonConvert.SerializeObject(root, settings);

        Console.WriteLine(json);
    }
}

class Location
{
    public Location()
    {
        Children = new List<Location>();
    }

    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
    public List<Location> Children { get; set; }
}

这是输出结果:

{
  "id": 1,
  "parentId": 1,
  "name": "TopLoc",
  "children": [
    {
      "id": 2,
      "parentId": 1,
      "name": "Loc1",
      "children": [
        {
          "id": 4,
          "parentId": 2,
          "name": "Loc1A",
          "children": []
        }
      ]
    },
    {
      "id": 3,
      "parentId": 1,
      "name": "Loc2",
      "children": []
    }
  ]
}

最佳反序列化方法是什么? - Rod
1
@Rod 要进行反序列化,你只需要执行 Location loc = JsonConvert.DeserializeObject<Location>(json); 即可。 - Brian Rogers
非常感谢:) - Rod
你有没有想法如何将层次结构(无论是JSON还是POCO)扁平化到数据库中?我正在尝试弄清楚如何将新的分层对象插入数据库(作为新记录)。 - Rod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接