C#中基于多层子模型的深层属性过滤优化方案咨询
多层Umbraco内容结构的高效过滤方案
问题背景
现有嵌套层级的Umbraco内容结构(国家→郡→城市→诊所→二级诊所→治疗菜单→治疗分类→治疗项),需要基于最底层TreatmentItem的SurgicalProcedure.Name属性筛选数据(例如筛选出所有关联SurgicalProcedure.Name == "Angioplasty"的国家相关数据)。原代码使用多层嵌套foreach,冗余且低效,需要更优实现方式。
原代码:
var treatmentItemss = new List<TreatmentItemViewModel>(); IEnumerable<IPublishedContent> countries = UmbracoContext.Content.GetById(contentId: 1063).Children(); foreach (var country in countries) { IEnumerable<IPublishedContent> countys = country.Children(); foreach (var county in countys) { IEnumerable<IPublishedContent> cities = county.Children(); foreach (var city in cities) { IEnumerable<IPublishedContent> clinics = city.Children(); foreach (var clinic in clinics) { IEnumerable<IPublishedContent> clinics2 = clinic.Children(); foreach (var clinic2 in clinics2) { IEnumerable<IPublishedContent> treatmentMenus = clinic2.Children(); foreach (var treatmentMenu in treatmentMenus) { IEnumerable<IPublishedContent> treatmentCategories = treatmentMenu.Children(); foreach (var treatmentCategory in treatmentCategories) { dynamic treatmentItems = treatmentCategory.Children(); foreach (var item in treatmentItems) { treatmentItemss.Add(new TreatmentItemViewModel { SurgicalProcedure = item.SurgicalProcedure?.Name, NonSurgicalTreatment = item.NonSurgicalTreatment?.Name, Title = item.Title, Id = item.Id, }); } } } } } } } }
优化实现方式
1. 使用Umbraco Descendants 直接定位目标节点
利用Umbraco内置的Descendants方法跳过多层遍历,结合LINQ完成筛选和投影,代码更简洁高效:
var rootNode = UmbracoContext.Content.GetById(1063); var filteredTreatmentItems = rootNode // 指定治疗项的文档类型别名(如"treatmentItem"),缩小遍历范围 .Descendants("treatmentItem") // 筛选符合条件的治疗项 .Where(item => item.Value<IPublishedContent>("surgicalProcedure")?.Name == "Angioplasty") // 投影为目标ViewModel .Select(item => new TreatmentItemViewModel { SurgicalProcedure = item.Value<IPublishedContent>("surgicalProcedure")?.Name, NonSurgicalTreatment = item.Value<IPublishedContent>("nonSurgicalTreatment")?.Name, Title = item.Value<string>("title"), Id = item.Id }) .ToList();
注意:
- 用强类型
Value<T>替代dynamic,避免运行时错误,提升代码可读性。 - 传入文档类型别名到
Descendants,能减少不必要的节点遍历,大幅提升性能。
2. 关联层级数据,获取所属国家信息
如果需要同时获取治疗项及其所属的国家数据,可通过Ancestor方法向上追溯层级:
var rootNode = UmbracoContext.Content.GetById(1063); var filteredItemsWithCountry = rootNode .Descendants("treatmentItem") .Where(item => item.Value<IPublishedContent>("surgicalProcedure")?.Name == "Angioplasty") .Select(item => new { TreatmentItem = new TreatmentItemViewModel { SurgicalProcedure = item.Value<IPublishedContent>("surgicalProcedure")?.Name, NonSurgicalTreatment = item.Value<IPublishedContent>("nonSurgicalTreatment")?.Name, Title = item.Value<string>("title"), Id = item.Id }, // 向上获取所属国家节点(需指定国家文档类型别名,如"country") CountryName = item.Ancestor("country")?.Name, CountryId = item.Ancestor("country")?.Id }) .ToList();
3. 自定义递归遍历(适合特殊层级逻辑)
如果需要灵活控制遍历规则,可编写递归方法:
public List<TreatmentItemViewModel> GetFilteredItems(IPublishedContent node, string targetProcedureName) { var result = new List<TreatmentItemViewModel>(); // 判断当前节点是否为治疗项 if (node.ContentType.Alias == "treatmentItem") { var procedure = node.Value<IPublishedContent>("surgicalProcedure"); if (procedure?.Name == targetProcedureName) { result.Add(new TreatmentItemViewModel { SurgicalProcedure = procedure.Name, NonSurgicalTreatment = node.Value<IPublishedContent>("nonSurgicalTreatment")?.Name, Title = node.Value<string>("title"), Id = node.Id }); } return result; } // 递归遍历子节点 foreach (var child in node.Children) { result.AddRange(GetFilteredItems(child, targetProcedureName)); } return result; } // 调用示例 var rootNode = UmbracoContext.Content.GetById(1063); var filteredItems = GetFilteredItems(rootNode, "Angioplasty");
性能优化建议
- 始终在
Descendants中指定文档类型别名,减少无效节点遍历。 - 避免使用
dynamic,坚持强类型Value<T>方法,提升代码稳定性与性能。 - 数据量较大时,缓存筛选结果,减少重复查询开销。
内容的提问来源于stack exchange,提问作者Okasha Momin
相关产品推荐
相关产品推荐

