简体   繁体   English

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

[英]How do I construct a nested, strongly typed object from a flat ("non-normalized") array?

I'm writing a .NET service to consume (GET) a JSON array from a web service containing data, which if in a database, would be normalized into separate related tables.我正在编写一个 .NET 服务来使用(GET)来自包含数据的 Web 服务的 JSON 数组,如果在数据库中,这些数据将被规范化为单独的相关表。 The JSON array will be coming in with each element repeating the parent data properties and only the childrens' properties will change from element to element. JSON 数组将与每个重复父数据属性的元素一起出现,并且只有子元素的属性会从元素到元素发生变化。 So here's what the JSON object will look like:所以这里是 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"
}]

But I need to transform this array (hopefully with Newtonsoft or Linq libraries?) into a .NET object that will look something like this:但是我需要将这个数组(希望使用 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; }
        }
    }
}

I've seen examples of doing the opposite;我见过相反的例子; flattening a nested object into a list-like object, but not what I'm looking for.将嵌套对象展平为类似列表的对象,但不是我要找的。 Again, I was hoping it could be accomplished by the Json libraries of Newtonsoft or plain Linq.再次,我希望它可以通过 Newtonsoft 或普通 Linq 的 Json 库来完成。 Thanks.谢谢。

I'm sure this can be done with Linq, but it's easily doable with just a loop, as this example code shows: 我敢肯定,这可以用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; }
        }
    }
}

Output: 输出:

在此处输入图片说明

Note: 注意:

This code handles multiple parents in one response, as although your question suggests that there is only one parent per response I wasn't completely sure. 这段代码可以在一个响应中处理多个父母,就像您的问题表明我不确定每个响应只有一个父母一样。

Both "Third childs" objects in JSON have different names "Third child" and "Third C hild" and different IDs 3 and 4, I made these fields same to get better result on output. JSON中的两个“ Third childs”对象都具有不同的名称“ Third child”和“ Third C hild”,并具有不同的ID 3和4,我将这些字段设置为相同,以获得更好的输出结果。

Also I used int? 我也用int? for IDs, because JSON has nullable int fields and Tuples (C# 7.0) instead anonymous objects. ID,因为JSON具有可为null的int字段和Tuples (C#7.0)而不是匿名对象。

You can remove Where filters to collect objects with null IDs also. 您可以删除Where的过滤器,以收集与无效的ID也对象。

Let me know if you have questions or need fixes, here is the code: 如果您有任何疑问或需要修复,请告诉我,这是代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何以层次结构显示非规范化数据? - How do I display non-normalized data in a hierarchical structure? 如何使用 C# MongoDB 驱动程序编写强类型过滤器,其中嵌套的 object 属性不能相等? - How to do I write a strongly typed filter where nested object properties cannot be equal using C# MongoDB driver? 如何从MarkupExtension返回强类型对象? - How to return strongly typed object from MarkupExtension? 如何制作强类型的 AuthorizeAttribute - How do I make a strongly typed AuthorizeAttribute 实体框架6.1上的非规范化表 - Non-normalized tables on Entity Framework 6.1 如何在mongodb中使用强类型查询构建器访问嵌套数组属性 - How to access nested array properties with strongly typed query builders in mongodb 将归一化的int转换为不以0开始的非归一化的int - Turning Normalized Int to Non-normalized Int That Doesnt Start At 0 似乎无法从数组反序列化为强类型列表对象 - cant seem to Deserialize to strongly typed list object from array 如何在多个强类型视图之间保留对象属性值? - How do I retain object property values between more than one strongly typed view? 如何使用接收强类型对象作为输入的WCF服务? - How do I consume a WCF service that receives a strongly-typed object as input?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM