Как создать ответ вложенного (родитель-ребенок) JSON в c #?

Я делаю веб-сервис, который даст ответ в формате JSON. Я загрузил данные с сервера sql и сохранил их в 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, являются родителями, и у них есть дети, у которых есть тот же 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 ответа


Перед сериализацией необходимо создать иерархию объектов. Для этого определите новое свойство в классе 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();
}

Демо здесь


Я думаю, что вы хотите иметь список папок внутри папки, например:

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

Когда вы используете JSONConvert в этом случае, вы можете столкнуться с наличием круговых зависимостей, если родительский объект существует в коллекции ребенка. Вы можете использовать объект SerializerSettings для игнорирования этих случаев, а для дочерних элементов в списке элементов вы можете установить свою коллекцию в нуль, поэтому она не будет сериализована.

Однако желаемый вывод, который вы укажете, также содержит список папок. Поэтому, в конце концов, вам потребуется сериализовать коллекцию (например, List или array) класса папки. Что-то вроде.

Что касается того, как вы загружаете данные, я думаю, вы уже загрузили папки с идентификатором, pid и заголовком, но свойство 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
    });

Есть идеи?

10000