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

如何向C# Dictionary值追加数组并实现PrestaShop NTree计算逻辑

需求1:向Dictionary<int, ComputeNTree>指定键追加ComputeNTreeIndexes数组元素

原示例代码存在两个需要修正的问题:

  • Dictionary不允许重复键调用Add方法,会抛出异常,需先判断键是否存在再操作
  • ComputeNTree的ComputeNTreeIndexes属性需要初始化,否则为null无法追加元素

修正后的类定义与实现代码

public class ComputeNTree
{
    // 推荐用List更方便追加,若必须用数组可保留,追加时转换即可
    public List<ComputeNTreeIndexes> ComputeNTreeIndexes { get; set; } = new List<ComputeNTreeIndexes>();
}

public class ComputeNTreeIndexes
{
    public int IdCategory { get; set; }
    public int Nleft { get; set; }
    public int Nright { get; set; }
}

追加元素逻辑

var dict = new Dictionary<int, ComputeNTree>();
int targetKey = 1;
// 先判断键是否存在,不存在则初始化
if (!dict.ContainsKey(targetKey))
{
    dict[targetKey] = new ComputeNTree();
}
// 追加3个元素的示例
dict[targetKey].ComputeNTreeIndexes.AddRange(new List<ComputeNTreeIndexes>
{
    new ComputeNTreeIndexes{ IdCategory = 12, Nleft = 1, Nright = 0 },
    new ComputeNTreeIndexes{ IdCategory = 14, Nleft = 2, Nright = 0 },
    new ComputeNTreeIndexes{ IdCategory = 16, Nleft = 4, Nright = 0 }
});

// 若必须保留数组类型的属性,追加逻辑如下:
// dict[targetKey].ComputeNTreeIndexes = dict[targetKey].ComputeNTreeIndexes
//     .Concat(new[]
//     {
//         new ComputeNTreeIndexes{ IdCategory = 12, Nleft = 1, Nright = 0 },
//         new ComputeNTreeIndexes{ IdCategory = 14, Nleft = 2, Nright = 0 },
//         new ComputeNTreeIndexes{ IdCategory = 16, Nleft = 4, Nright = 0 }
//     }).ToArray();

需求2:PrestaShop嵌套集重建逻辑C#实现

核心逻辑完全对齐PHP版本的前序遍历规则,左值进入节点时赋值,右值在所有子节点遍历完成后赋值,和PrestaShop原生逻辑一致。

核心递归函数实现

/// <summary>
/// 递归计算嵌套集左右值
/// </summary>
/// <param name="categories">父分类ID对应子分类ID列表的映射,对应PHP的$categoriesArray</param>
/// <param name="idCategory">当前计算的分类ID</param>
/// <param name="n">左右值计数器,按引用传递</param>
/// <returns>所有分类的ID、左值、右值集合</returns>
protected static List<(int IdCategory, int Nleft, int Nright)> ComputeNTreeInfos(
    Dictionary<int, List<int>> categories, 
    int idCategory, 
    ref int n)
{
    var result = new List<(int, int, int)>();
    int left = n++;
    // 存在子分类则递归遍历
    if (categories.TryGetValue(idCategory, out var subCategories))
    {
        foreach (var subId in subCategories)
        {
            result.AddRange(ComputeNTreeInfos(categories, subId, ref n));
        }
    }
    int right = n++;
    result.Add((idCategory, left, right));
    return result;
}

完整嵌套集重建逻辑

public static void RegenerateEntireNtree()
{
    // 替换为项目自身的店铺ID获取逻辑,对应PHP的上下文读取和配置读取
    int idShop = GetCurrentShopId() ?? GetDefaultShopId();
    
    // 1. 从数据库读取分类数据,对应PHP的SQL查询逻辑,实际项目替换为自身的ORM/ADO查询
    var categoryList = _dbContext.CategoryShop
        .Join(_dbContext.Categories,
            cs => cs.IdCategory,
            c => c.IdCategory,
            (cs, c) => new { c.IdCategory, c.IdParent, cs.Position })
        .Where(cs => cs.IdShop == idShop)
        .OrderBy(c => c.IdParent)
        .ThenBy(c => c.Position)
        .Select(c => new { c.IdCategory, c.IdParent })
        .ToList();
    
    // 2. 组装父分类对应子分类列表的映射,对应PHP的$categoriesArray组装
    var categoriesMap = new Dictionary<int, List<int>>();
    foreach (var cate in categoryList)
    {
        if (!categoriesMap.ContainsKey(cate.IdParent))
        {
            categoriesMap[cate.IdParent] = new List<int>();
        }
        categoriesMap[cate.IdParent].Add(cate.IdCategory);
    }
    
    // 3. 递归计算左右值
    if (categoriesMap.TryGetValue(0, out var rootCategories) && rootCategories.Any())
    {
        int n = 1;
        // 取根节点第一个分类开始计算,和PHP逻辑一致
        var nTreeData = ComputeNTreeInfos(categoriesMap, rootCategories[0], ref n);
        
        // 4. 分批写入数据库,对应PHP的分块插入逻辑
        const int batchSize = 5000;
        for (int i = 0; i < nTreeData.Count; i += batchSize)
        {
            var batch = nTreeData.Skip(i).Take(batchSize).ToList();
            // 实际项目建议使用参数化查询/ORM批量扩展,避免SQL注入风险
            var values = string.Join(",", batch.Select(x => $"({x.IdCategory},{x.Nleft},{x.Nright})"));
            var sql = $@"INSERT INTO category (id_category, nleft, nright)
                VALUES {values}
                ON DUPLICATE KEY UPDATE nleft=VALUES(nleft), nright=VALUES(nright)";
            _dbContext.Database.ExecuteSqlRaw(sql);
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 15:54:03