You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:C#中如何将OData返回的商品类目构建为层级树形结构

问题描述

我正在开发一款C#应用,某方法会获取OData响应体,响应体代表商品类目,类目间的父子关系由Parent_Category字段定义。最终目标是向用户展示类目的树形视图,现在想先实现文本形式的层级列表(示例如下),再推进UI树形视图的开发。

示例文本层级:

BEANS
CM
--> CM_COMMER
--> CM_CONSUM
FASHION
FURNITURE
--> CHAIR
--> DESK
--> TABLE
MISC
--> SUPPLIERS
PARTS

OData响应体:

{
"@odata.context": "https://api.businesscentral.dynamics.com/v2.0/13bb3475-ed48-4836-8e0d-6188cc004599/Sandbox2/ODataV4/$metadata#Company('CRONUS%20USA%2C%20Inc.')/ItemCategories",
"value": [
    {
        "@odata.etag": "W/\"JzE5Ozc0MDEzNzM2MzQ2Mjc3MDQ5MzQxOzAwOyc=\"",
        "Code": "BEANS",
        "Description": "BEANS",
        "Parent_Category": "",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzE4OzU5MTI1NDIzNTQ0MDU4MDc2OTE7MDA7Jw==\"",
        "Code": "CM",
        "Description": "Coffee Makers",
        "Parent_Category": "",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzIwOzE3MzEyMjA5NzY5NzA2NzQ1MjYyMTswMDsn\"",
        "Code": "CM_COMMER",
        "Description": "Commercial Models",
        "Parent_Category": "CM",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzE4OzkyNzkxOTcxNzAyNjYyMTI3ODE7MDA7Jw==\"",
        "Code": "CM_CONSUM",
        "Description": "Consumer Models",
        "Parent_Category": "CM",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzIwOzEyODQzNzYyMTU3OTI4NTE5Mzk1MTswMDsn\"",
        "Code": "FASHION",
        "Description": "Fashion Jewelry",
        "Parent_Category": "",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzIwOzEyMjU5NzE2Njg0MzE3ODg3MTc4MTswMDsn\"",
        "Code": "FURNITURE",
        "Description": "Office Furniture",
        "Parent_Category": "",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzIwOzE0NTg1NTU0Njg2NjkzNzc2MjM1MTswMDsn\"",
        "Code": "CHAIR",
        "Description": "Office Chair",
        "Parent_Category": "FURNITURE",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzE4OzkyMzYzNjkwNTExMzY3MzAwMDE7MDA7Jw==\"",
        "Code": "DESK",
        "Description": "Office Desk",
        "Parent_Category": "FURNITURE",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzIwOzExNzIzNjI3NzUxMjcxMTI2MjY3MTswMDsn\"",
        "Code": "TABLE",
        "Description": "Assorted Tables",
        "Parent_Category": "FURNITURE",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzE2Ozc3MjM1ODY4ODY4MDQyNjcxOzAwOyc=\"",
        "Code": "MISC",
        "Description": "Miscellaneous",
        "Parent_Category": "",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzE5OzU0NjM3MTMyNTc0NDI5MDk0NDIxOzAwOyc=\"",
        "Code": "SUPPLIERS",
        "Description": "Office Supplies",
        "Parent_Category": "MISC",
        "LSE_Outbound_Code": ""
    },
    {
        "@odata.etag": "W/\"JzIwOzEyNDU0NDkzNDczMDM2NjAxNDk4MTswMDsn\"",
        "Code": "PARTS",
        "Description": "Parts",
        "Parent_Category": "",
        "LSE_Outbound_Code": ""
    }
]
}
实现步骤与代码示例

1. 定义类目模型类

先创建对应OData响应结构的类,方便序列化和后续操作:

using System.Text.Json.Serialization;

public class ItemCategory
{
    public string Code { get; set; }
    public string Description { get; set; }
    public string Parent_Category { get; set; }
    
    [JsonPropertyName("@odata.etag")]
    public string ODataEtag { get; set; }
}

public class ODataResponse
{
    [JsonPropertyName("@odata.context")]
    public string ODataContext { get; set; }
    public List<ItemCategory> value { get; set; }
}

2. 构建树形结构

将扁平的类目列表转换为树形结构,添加一个带子节点的扩展类:

public class CategoryNode
{
    public ItemCategory Category { get; set; }
    public List<CategoryNode> Children { get; set; } = new List<CategoryNode>();
}

然后实现构建树形结构的方法:

public static List<CategoryNode> BuildCategoryTree(List<ItemCategory> categories)
{
    // 建立Code到节点的映射,快速查找父节点
    var nodeMap = categories.ToDictionary(cat => cat.Code, cat => new CategoryNode { Category = cat });
    var rootNodes = new List<CategoryNode>();
    
    foreach (var category in categories)
    {
        if (string.IsNullOrEmpty(category.Parent_Category))
        {
            // 无父类目,加入根节点列表
            rootNodes.Add(nodeMap[category.Code]);
        }
        else
        {
            // 找到父节点并添加为子节点
            if (nodeMap.TryGetValue(category.Parent_Category, out var parentNode))
            {
                parentNode.Children.Add(nodeMap[category.Code]);
            }
        }
    }
    
    return rootNodes;
}

3. 递归生成文本层级列表

写递归方法遍历树形结构,生成指定格式的文本:

public static void GenerateTextHierarchy(List<CategoryNode> rootNodes, int indentLevel = 0, string indentSymbol = "--> ")
{
    foreach (var node in rootNodes)
    {
        // 根据层级生成缩进
        var indent = indentLevel > 0 ? string.Concat(Enumerable.Repeat(indentSymbol, indentLevel)) : "";
        Console.WriteLine($"{indent}{node.Category.Code}");
        
        // 递归处理子节点,层级+1
        if (node.Children.Any())
        {
            GenerateTextHierarchy(node.Children, indentLevel + 1, indentSymbol);
        }
    }
}

4. 完整调用流程

// 假设已获取OData响应JSON字符串,这里模拟解析
var oDataJson = "你的OData响应JSON字符串";
var oDataResponse = System.Text.Json.JsonSerializer.Deserialize<ODataResponse>(oDataJson);

// 构建树形结构
var categoryTree = BuildCategoryTree(oDataResponse.value);

// 生成文本层级
GenerateTextHierarchy(categoryTree);

运行后会输出符合要求的文本层级:

BEANS
CM
--> CM_COMMER
--> CM_CONSUM
FASHION
FURNITURE
--> CHAIR
--> DESK
--> TABLE
MISC
--> SUPPLIERS
PARTS

关键思路说明

  • 映射表优化:用Dictionary建立类目Code到节点的映射,避免重复遍历列表,提升处理效率
  • 递归遍历:通过递归自动处理层级缩进,逻辑简洁清晰,适配任意深度的类目结构
  • 扩展性:构建的树形结构可直接复用在后续UI树形视图开发中,只需将生成文本的逻辑替换为UI节点创建逻辑

内容的提问来源于stack exchange,提问作者gregarican

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:32:39