如何从平面(“非规范化”)数组构造嵌套的强类型对象?

时间:2019-02-01 16:36:14

标签: c# arrays .net json linq

我正在编写.NET服务,以使用(获取)来自包含数据的Web服务的JSON数组,如果在数据库中,则将其标准化为单独的相关表。 JSON数组将随每个元素重复父数据属性而出现,只有子元素的属性会在元素之间变化。所以这是JSON对象的样子:

[  {
    "parentID": 123,
    "parentName": "Parent Name",
    "childID": 1,
    "childName": "First Child",
    "subChildID": null,
    "subChildName": null
},
{
    "parentID": 123,
    "parentName": "Parent Name",
    "childID": 2,
    "childName": "Second Child",
    "subChildID": null,
    "subChildName": null
},
{
    "parentID": 123,
    "parentName": "Parent Name",
    "childID": 3,
    "childName": "Third Child",
    "subChildID": 100,
    "subChildName": "First Subchild of the third child"
},
{
    "parentID": 123,
    "parentName": "Parent Name",
    "childID": 4,
    "childName": "Third child",
    "subChildID": 101,
    "subChildName": "Second subchild of the third child"
}]

但是我需要将此数组(希望是使用Newtonsoft或Linq库吗?)转换成一个.NET对象,它看起来像这样:

public class ParentObject
{
    public int parentID { get; set; }
    public string parentName { get; set; }
    public List<ChildObject> children { get; set; }

    private class ChildObject
    {
        public int childID { get; set; }
        public string childName { get; set; }
        public List<SubChildObject> subChildren { get; set; }

        private class SubChildObject
        {
            public int subChildID { get; set; }
            public string subChildName { get; set; }
        }
    }
}

我看到了相反的例子;将嵌套对象展平为类似列表的对象,但不是我要的对象。同样,我希望可以通过Newtonsoft或纯Linq的Json库来实现。谢谢。

2 个答案:

答案 0 :(得分:1)

我确定可以使用Linq完成此 ,但是只需循环即可轻松实现,如以下示例代码所示:

List<ParentObject> CreateEntities(string json)
{
    var entities = JsonConvert.DeserializeObject<List<RootObject>>(json);
    List<ParentObject> parents = new List<ParentObject>();

    foreach (var entity in entities)
    {
        if (parents.Any(p => p.parentID == entity.parentID))
        {
            var parent = parents.Single(p => p.parentID == entity.parentID);

            if (parent.children.Any(c => c.childID == entity.childID))
            {
                var child = parent.children.Single(c => c.childID == entity.childID);
                if (entity.subChildID.HasValue)
                {
                    child.subChildren.Add(new ParentObject.ChildObject.SubChildObject
                    {
                        subChildID = entity.subChildID.Value,
                        subChildName = entity.subChildName
                    });
                }
            }
            else
            {
                var newChild = (new ParentObject.ChildObject
                {
                    childID = entity.childID,
                    childName = entity.childName,
                    subChildren = new List<ParentObject.ChildObject.SubChildObject>()
                });


                if (entity.subChildID.HasValue)
                {
                    newChild.subChildren.Add(new ParentObject.ChildObject.SubChildObject
                    {
                        subChildID = entity.subChildID.Value,
                        subChildName = entity.subChildName
                    });
                }

                parent.children.Add(newChild);
            }
        }
        else
        {
            var newParent = new ParentObject
            {
                parentID = entity.parentID,
                parentName = entity.parentName,
                children = new List<ParentObject.ChildObject>
                {
                    new ParentObject.ChildObject
                    {
                        childID = entity.childID,
                        childName = entity.childName,
                        subChildren = new List<ParentObject.ChildObject.SubChildObject>()
                    }
                }
            };

            if (entity.subChildID.HasValue)
            {
                newParent.children.Single().subChildren.Add(new ParentObject.ChildObject.SubChildObject
                {
                    subChildID = entity.subChildID.Value,
                    subChildName = entity.subChildName
                });
            }

            parents.Add(newParent);
        }
    }

    return parents;
}

public class RootObject
{
    public int parentID { get; set; }
    public string parentName { get; set; }
    public int childID { get; set; }
    public string childName { get; set; }
    public int? subChildID { get; set; }
    public string subChildName { get; set; }
}

public class ParentObject
{
    public int parentID { get; set; }
    public string parentName { get; set; }
    public List<ChildObject> children { get; set; }

    public class ChildObject
    {
        public int childID { get; set; }
        public string childName { get; set; }
        public List<SubChildObject> subChildren { get; set; }

        public class SubChildObject
        {
            public int subChildID { get; set; }
            public string subChildName { get; set; }
        }
    }
}

输出:

enter image description here

注意:

此代码可在一个响应中处理多个父母,就像您的问题表明我不确定每个响应只有一个父母一样。

答案 1 :(得分:1)

JSON中的“第三个孩子”对象都具有不同的名称“第三个孩子”和“第三个 C hild”以及不同的ID 3和4,我将这些字段设置为相同,以获得更好的输出结果。

我还使用int?作为ID,因为JSON具有可空的int字段和Tuples(C#7.0)而不是匿名对象。

您可以删除Where过滤器来收集ID为空的对象。

如果您有任何疑问或需要修复,请告诉我,这是代码:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            string json = @"[
                             {
                                 ""parentID"": 123,
                                 ""parentName"": ""Parent Name"",
                                 ""childID"": 1,
                                 ""childName"": ""First Child"",
                                 ""subChildID"": null,
                                 ""subChildName"": null
                             },
                             {
                                 ""parentID"": 123,
                                 ""parentName"": ""Parent Name"",
                                 ""childID"": 2,
                                 ""childName"": ""Second Child"",
                                 ""subChildID"": null,
                                 ""subChildName"": null
                             },
                             {
                                 ""parentID"": 123,
                                 ""parentName"": ""Parent Name"",
                                 ""childID"": 3,
                                 ""childName"": ""Third child"",
                                 ""subChildID"": 100,
                                 ""subChildName"": ""First Subchild of the third child""
                             },
                             {
                                 ""parentID"": 123,
                                 ""parentName"": ""Parent Name"",
                                 ""childID"": 3,
                                 ""childName"": ""Third child"",
                                 ""subChildID"": 101,
                                 ""subChildName"": ""Second subchild of the third child""
                             }
                            ]";

            JArray jarr = JArray.Parse(json);

            IEnumerable<ParentObject> parents = jarr.GroupBy(t => ((int?)t["parentID"], (string)t["parentName"]))
                                                    .Select(pg => new ParentObject
                                                    {
                                                        parentID = pg.Key.Item1,
                                                        parentName = pg.Key.Item2,
                                                        children = pg
                                                    .GroupBy(t => ((int?)t["childID"], (string)t["childName"]))
                                                    .Select(cg => new ParentObject.ChildObject()
                                                    {
                                                        childID = cg.Key.Item1,
                                                        childName = cg.Key.Item2,
                                                        subChildren = cg
                                                    .Select(t => new ParentObject.ChildObject.SubChildObject()
                                                    {
                                                        subChildID = (int?)t["subChildID"],
                                                        subChildName = (string)t["subChildName"]
                                                    }).Where(s => s.subChildID != null).ToList()
                                                    }).Where(c => c.childID != null).ToList()
                                                    }).Where(p => p.parentID != null).ToList();

            json = JsonConvert.SerializeObject(parents, Formatting.Indented);

            Console.WriteLine(json);

            Console.ReadKey();
        }
    }

    public class ParentObject
    {
        public int? parentID { get; set; }
        public string parentName { get; set; }
        public List<ChildObject> children { get; set; }

        public class ChildObject
        {
            public int? childID { get; set; }
            public string childName { get; set; }
            public List<SubChildObject> subChildren { get; set; }

            public class SubChildObject
            {
                public int? subChildID { get; set; }
                public string subChildName { get; set; }
            }
        }
    }
}