如何在C#中创建嵌套的(parent-Child)JSON响应?

时间:2018-10-17 19:51:15

标签: c# json visual-studio linq

我正在制作一个Web服务,它将以JSON格式给出响应。我已经从SQL Server提取了数据并将其存储在Datatable中。 dt的外观如下:-

id      Caption                 pid
F182    GLOBAL REPORTS          NULL
F184    software                NULL
F1227   LYB P&L Reports         F184
F1245   LYB Training            F184
F1239   test3                   F182
F1249   Paavan_Test_Reports     F184
标题栏中

pid为 Null 的项是父项,并且其子项与各自父级的 id 具有相同的 pid

例如: GLOBAL REPORTS 有1个孩子,即 test3 软件有3个孩子。

我希望JSON响应采用以下格式

[{ 
    id='F182',  
    caption='GLOBAL REPORTS',
    pid=null;
    items:[{
    id='F1239',
    caption='test3',
    pid='F182'}] 
    },
    { 
    id='F184',
    caption='software',
    pid='NULL',
    items:[{
    id='F1227',
    caption='LYB P&L Reports',
    pid='F184'
    },
    {
    id='F1245',
    caption='LYB Training',
    pid='F184'
    },
    { 
    id='F1249',
    caption='Paavan_Test_Reports',
    pid='F184'
    }
}]

我已经制作了一个类文件夹

    class folder
    {
    string id{get;set;}
    string pid{get;set;}
    string caption{get;set;}
   }

如何获取对象数组,其中将包含特定父级的所有可用子级?我是Json对象和响应的新手,

我尝试使用以下方法:

 var obj = dt.AsEnumerable()
                .GroupBy(r => r["pid"])
                .ToDictionary(g => g.Key.ToString(),
                              g => g.Select(r => new {
                              item = r["caption"].ToString(),
                              }).ToArray());
     var json = JsonConvert.SerializeObject(obj);

但这给了我一个简单的json响应,没有任何层次。

2 个答案:

答案 0 :(得分:3)

您需要在序列化之前构建对象层次结构。为此,请在您的folder类中定义一个新属性:

public IEnumerable<folder> items { get; set; }

现在,您可以递归搜索每个根folder的子对象:

public static IEnumerable<folder> BuildTree(folder current, folder[] allItems)
{
    var childs = allItems.Where(c => c.pid == current.id).ToArray();
    foreach (var child in childs)
        child.items = BuildTree(child, allItems);
    current.items = childs;
    return childs;
}

用法:

var input = new[] // dt.AsEnumerable() in your case
{
    new folder {id = "F182",  caption = "GLOBAL REPORTS",      pid = null   },
    new folder {id = "F184",  caption = "software",            pid = null   },
    new folder {id = "F1227", caption = "LYB P&L Reports",     pid = "F184" },
    new folder {id = "F1245", caption = "LYB Training",        pid = "F184" },
    new folder {id = "F1239", caption = "test3",               pid = "F182" },
    new folder {id = "F1249", caption = "Paavan_Test_Reports", pid = "F184" },
};

var roots = input.Where(i => i.pid == null);
foreach (var root in roots)
    BuildTree(root, input);

var json = JsonConvert.SerializeObject(roots, Formatting.Indented);

此外,如果您想隐藏空的items,则可以在ShouldSerialize类中定义方法folder

public bool ShouldSerializeitems()
{
    return items.Any();
}

演示是here

答案 1 :(得分:2)

我认为您想要的是在文件夹中包含一个文件夹列表,如下所示:

class folder
{
    string id{get;set;}
    string pid{get;set;}
    string caption{get;set;}
    List<folder> items {get;set;}
}

在这种情况下使用JSONConvert时,如果在子级集合中存在父级,则可能会遇到循环依赖项。您可以使用SerializerSettings对象忽略这些情况,对于项列表中的子项,可以将其集合设置为null,这样就不会序列化。

但是,您指定的所需输出也会列出文件夹的数组。因此,最后,您需要序列化文件夹类的集合(例如,列表或数组)。像

关于如何加载数据,我想您已经加载了具有id,pid和caption的文件夹,但是items属性为空。

为了建立父子关系,您可以这样

var folders = dt.AsEnumerable().ToList();

foreach(var folder in folders) {
    folder.items = folders.Where(f => f.pid.Equals(folder.id)).ToList();
}

var parentFolders = folders.Where(f => f.pid is null);

var json = JsonConvert.SerializeObject(parentFolders, new SerializerSettings () {
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });