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

如何简化含多层子查询的Linq语句并提升性能?

优化OnBase Hyland API对接的LINQ语句及性能提升方案

问题背景

对接OnBase Hyland API与数据库筛选字段列表时,现有LINQ语句存在多层嵌套遍历导致性能低下,且fieldsList1.AddRange(fieldAsAttribute.ToList())无法正常工作(返回的是嵌套匿名类型集合而非目标Models.Field集合),需要简化语句并提升性能。

相关类定义

数据库字段实体类

public partial class field
{
     public long field_id { get; set; } 
     public string field_name { get; set; }
     public bool kw_flag { get; set; }
     public string kw_name { get; set; }
     public bool wv_flag { get; set; }
     public string wv_app { get; set; }
     public string wv_class { get; set; }
     public string wv_attr { get; set; }
     public string wv_dataset_name { get; set; }
     public string wv_filter_app { get; set; }
}

OnBase Hyland核心对象类

// Application相关定义
public  class Application 
{     
    public ClassList Classes;
    public FilterList Filters;
    public long ID { get; internal set; }
    public string Name { get; internal set; }
}

// Class相关定义
public class Class 
{
    public AttributeList Attributes;
    public long ID { get; internal set; }
    public string Name { get; internal set; }
    internal Application WVApplication { get; set; }
}

// Attribute相关定义
public sealed class Attribute  
{
    public Class Class => base.Application.WorkView.GetClassByID(ClassID);
    internal long ClassID { get; set; }
}

// 容器类属性
public KeywordTypeList KeywordTypes => _keywordTypeList ?? (_keywordTypeList = new KeywordTypeListImplementation(base.Application));
public ApplicationList Applications => _applications ?? (_applications = new ApplicationListImplementation(base.Application));

优化方案及代码实现

1. 核心优化思路

  • 扁平化集合:使用SelectMany替代多层嵌套遍历,直接提取目标Models.Field对象
  • 预构建索引:将频繁查询的对象(Application、Class、Filter)转为字典/Lookup,避免重复遍历
  • 延迟执行:减少不必要的ToList()调用,仅在最终需要物化集合时执行

2. 优化后的完整代码

// 1. 预构建索引,避免重复遍历查询
var appDict = app.WorkView.Applications.ToDictionary(a => a.Name, a => a);
var classLookup = app.WorkView.Applications
    .SelectMany(a => a.Classes, (app, cls) => new { AppName = app.Name, Class = cls })
    .ToLookup(x => (x.AppName, x.Class.Name), x => x.Class);
// 预构建每个Application的Filter字典
var appFilterDict = app.WorkView.Applications.ToDictionary(
    a => a.Name,
    a => a.Filters.ToDictionary(f => f.Name, f => f.ID)
);

var fieldsList = new List<Models.Field>();

// 2. 简化LINQ查询,直接扁平化提取目标对象
var targetFields = filteredFields
    // 仅处理wv_flag为true的字段(按需启用)
    .Where(f => f.wv_flag)
    // 匹配对应的Application
    .Where(f => appDict.ContainsKey(f.wv_app))
    .Select(f => new { FilteredField = f, App = appDict[f.wv_app] })
    // 匹配对应的Class
    .Where(x => classLookup.ContainsKey((x.App.Name, x.FilteredField.wv_class)))
    .SelectMany(x => classLookup[(x.App.Name, x.FilteredField.wv_class)], (x, cls) => new { x.FilteredField, x.App, Class = cls })
    // 匹配对应的Attribute
    .Where(x => x.Class.Attributes.Any(attr => attr.Name == x.FilteredField.wv_attr))
    // 构建目标Models.Field对象
    .Select(x => new Models.Field
    {
        FieldId = x.FilteredField.field_id,
        Name = x.FilteredField.field_name,
        HasDropdown = true,
        // 从预构建的字典中直接获取FilterID,避免重复查询
        DropdownId = appFilterDict[x.App.Name].TryGetValue(x.FilteredField.wv_filter, out var filterId) 
            ? filterId 
            : 0, // 或根据业务设置默认值
        DropdownType = Models.Field.DropdownTypeEnum.FilterEnum
    });

// 3. 直接添加到列表,解决AddRange失效问题
fieldsList.AddRange(targetFields);

3. 关键优化点说明

  • 预构建索引:将Application、Class、Filter转为字典/Lookup后,查询时间复杂度从O(n)降为O(1),大幅减少重复遍历开销
  • 扁平化查询:通过SelectMany直接将多层嵌套的集合转为单层Models.Field集合,无需手动三层foreach,代码更简洁且性能更高
  • 避免空引用风险:使用TryGetValue替代SingleOrDefault(),防止Filter不存在时出现空引用异常
  • 减少不必要的物化:仅在最终AddRange时才执行查询,充分利用LINQ的延迟执行特性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 19:06:07