如何从含parent_id的地理数据生成层级化URL?
问题描述
现有一张混合存储国家、城市、次级城市等地理数据的表,示例数据如下:
Name | id | parent_id 1) united kingdom | 1 | 0; 2) london | 2 | 1; 3) south london | 3 | 2;
需为每个城市生成层级化URL,例如伦敦南部的URL为:
/united-kingdom/london/south-london
目前通过以下代码从服务获取Geo对象列表,每个对象包含id和parentId(国家的parentId为null),请教如何基于这些数据创建上述层级结构?
var geoSolution = await _geoService.GetGeoChildren(selectedCountry, culture, cancellationToken); foreach (var geo in geoSolution.Value ?? Enumerable.Empty<Geo>()) { if (geo.ParentId == null) continue; sitemapList.Add(new SitemapHtml(geo.GeoName ?? string.Empty, GetPrefix(geo.Name ?? string.Empty, product ?? "")) { Links = await GetSitemapLinksForGeo(urlSections, geo, cancellationToken, true) }); } return sitemapList.OrderBy(x => x.Name).ToList();
注:geoSolution返回的Geo对象列表中,国家类型的对象parentId为null。
解决方案
要生成层级化URL,核心是为每个Geo对象回溯完整的父级链,将链中每个节点的名称转换为URL友好格式后拼接成路径。
1. 构建Geo对象映射字典
先把所有Geo对象存入字典,方便通过id快速查找父节点:
var allGeoItems = geoSolution.Value ?? Enumerable.Empty<Geo>(); // 以Geo的Id为键,建立快速查找映射 var geoById = allGeoItems.ToDictionary(g => g.Id, g => g);
2. 编写层级URL生成方法
用迭代方式向上遍历父节点,收集并格式化路径段,避免递归栈溢出问题:
private string BuildHierarchicalUrl(Geo geo, Dictionary<int, Geo> geoById) { var pathSegments = new List<string>(); var currentGeo = geo; // 从当前节点向上遍历至根节点(国家) while (currentGeo != null) { // 将名称转为URL友好格式:小写、空格替换为连字符,跳过空值 var urlSegment = currentGeo.Name?.Trim().ToLower().Replace(" ", "-") ?? string.Empty; if (!string.IsNullOrEmpty(urlSegment)) { pathSegments.Add(urlSegment); } // 终止条件:当前是国家节点(ParentId为null) if (currentGeo.ParentId == null) { break; } // 查找父节点 geoById.TryGetValue(currentGeo.ParentId.Value, out currentGeo); } // 反转路径段,得到从根到子的顺序 pathSegments.Reverse(); // 拼接成完整URL路径 return "/" + string.Join("/", pathSegments); }
3. 集成到现有代码中
修改原有循环逻辑,调用生成方法替换原有的GetPrefix:
var geoSolution = await _geoService.GetGeoChildren(selectedCountry, culture, cancellationToken); var allGeoItems = geoSolution.Value ?? Enumerable.Empty<Geo>(); var geoById = allGeoItems.ToDictionary(g => g.Id, g => g); foreach (var geo in allGeoItems) { if (geo.ParentId == null) continue; // 跳过国家节点,仅处理城市及次级节点 // 生成层级化URL var hierarchicalUrl = BuildHierarchicalUrl(geo, geoById); sitemapList.Add(new SitemapHtml(geo.GeoName ?? string.Empty, hierarchicalUrl) { Links = await GetSitemapLinksForGeo(urlSections, geo, cancellationToken, true) }); } return sitemapList.OrderBy(x => x.Name).ToList();
注意事项
- 若
GetPrefix有其他业务逻辑,可将层级URL与原有前缀拼接,按需调整 - 需处理名称为空的极端情况,避免生成无效的URL段
- 迭代方式比递归更适合大数据量场景,防止栈溢出
内容的提问来源于stack exchange,提问作者slowpoke
相关产品推荐
相关产品推荐

