LINQ Select中如何忽略连接对象获取List<ValidationRule>结果
LINQ查询多对多关联表返回嵌套集合问题
问题背景
使用LINQ/Lambda表达式从对象中拉取数据时,存在一个用于连接两类表/对象的中间连接表(连接类)。已实现基础的记录拉取逻辑,但返回结果为List<IEnumerable<ValidationRule>>类型,期望忽略中间连接对象,直接获取List<ValidationRule>类型的结果。
当前编写的代码如下:
public static List<ValidationRule> GetValidations(string fieldName, Dictionary<string, DataMappingPolicy> dataMappingPolicies) { List<ValidationRule> validationRules = new List<ValidationRule>(); var policyValidations = dataMappingPolicies.Where(_ => _.Key == fieldName).Select(_ => _.Value.PolicyValidationRules.Select(_ => _.ValidationRule)).ToList(); return validationRules; }
涉及的类定义如下:DataMappingPolicy类:
public class DataMappingPolicy { public DataMappingPolicy() { this.PolicyValidationRules = new HashSet<PolicyValidationRule>(); } public Guid DataMappingPolicyId { get; set; } public ICollection<PolicyValidationRule> PolicyValidationRules { get; set; } }
PolicyValidationRule中间连接类:
public class PolicyValidationRule { public Guid PolicyValidationRuleId { get; set; } public Guid DataMappingPolicyId { get; set; } public DataMappingPolicy DataMappingPolicy { get; set; } public Guid ValidationRuleId { get; set; } public ValidationRule ValidationRule { get; set; } }
问题原因
- 嵌套使用
Select会生成「序列的序列」:外层Select会为每个匹配到的键值对返回一个独立的IEnumerable<ValidationRule>序列,最终调用ToList()后得到的就是嵌套的List<IEnumerable<ValidationRule>>结构。 - 代码中初始化的空
validationRules列表没有接收任何查询结果,最终返回的是空列表,和查询逻辑完全脱节。
修复方案
使用SelectMany替代内层Select,该方法可以将多层嵌套的集合拍平为单层集合,直接得到目标类型的结果。
基础修复版本(保留原有Where查询逻辑):
public static List<ValidationRule> GetValidations(string fieldName, Dictionary<string, DataMappingPolicy> dataMappingPolicies) { var validationRules = dataMappingPolicies .Where(kvp => kvp.Key == fieldName) // SelectMany将每个policy下的验证规则直接合并到同一个顶层序列 .SelectMany(kvp => kvp.Value.PolicyValidationRules.Select(pvr => pvr.ValidationRule)) .ToList(); return validationRules; }
性能优化版本(利用Dictionary键唯一的特性,避免全字典遍历):
public static List<ValidationRule> GetValidations(string fieldName, Dictionary<string, DataMappingPolicy> dataMappingPolicies) { // 直接通过键取值,时间复杂度O(1),效率远高于Where遍历的O(n) if (!dataMappingPolicies.TryGetValue(fieldName, out var targetPolicy)) { return new List<ValidationRule>(); } return targetPolicy.PolicyValidationRules .Select(pvr => pvr.ValidationRule) .ToList(); }
说明:
SelectMany是LINQ中处理多对多关联、拍平嵌套集合的标准方法,会遍历外层序列的每个元素,将每个元素对应内层序列的所有元素逐个添加到最终返回的单层级序列中,不会保留中间连接层的结构。
内容的提问来源于stack exchange,提问作者K.Z
相关产品推荐
相关产品推荐

