Conversation
DHR60
commented
Feb 28, 2026
- 放宽组类型限制,允许作为前置/落地/路由规则节点
- 从 List indexId 中读取 List 时使用 GetProfileItemsOrderedByIndexIds,大幅度减小读取数据库次数。上次测的 2000 个节点读取耗时约减小了 85%。400 ms -> 50 ms
There was a problem hiding this comment.
Pull request overview
本 PR 旨在放宽“组类型”节点在前置/落地/路由规则等场景中的选择限制,并通过批量按 IndexId 读取 ProfileItem 来显著减少数据库访问次数,从而提升大规模节点场景下的性能。
Changes:
- 调整多个选择窗口的 ConfigType 过滤逻辑,允许选择组类型相关节点(仅排除 Custom)。
- 在多个 ViewModel/Manager 中将逐个
GetProfileItem查询改为批量查询并按输入 IndexId 顺序返回。 - 新增
AppManager.GetProfileItemsOrderedByIndexIds以支持“按 IndexId 列表顺序”获取 ProfileItem 列表。
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| v2rayN/v2rayN/Views/SubEditWindow.xaml.cs | 放宽前置/落地选择的类型过滤(仅排除 Custom) |
| v2rayN/v2rayN/Views/AddGroupServerWindow.xaml.cs | 放宽组节点添加子节点时的类型过滤(统一仅排除 Custom) |
| v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs | Desktop 端同步放宽前置/落地选择过滤 |
| v2rayN/v2rayN.Desktop/Views/AddGroupServerWindow.axaml.cs | Desktop 端同步放宽组节点添加子节点过滤 |
| v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs | 选中项读取改为批量按 IndexId 获取,减少 DB 次数 |
| v2rayN/ServiceLib/ViewModels/ProfilesSelectViewModel.cs | 多选读取改为批量按 IndexId 获取,减少 DB 次数 |
| v2rayN/ServiceLib/ViewModels/AddGroupServerViewModel.cs | 初始化子节点列表改为批量按 IndexId 获取,减少 DB 次数 |
| v2rayN/ServiceLib/Manager/GroupProfileManager.cs | Cycle 检测与子节点获取路径改为批量查询/按序返回 |
| v2rayN/ServiceLib/Manager/AppManager.cs | 新增 GetProfileItemsOrderedByIndexIds 承载批量按序读取能力 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var idList = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); | ||
| if (idList.Count == 0) | ||
| { | ||
| return []; | ||
| } | ||
|
|
||
| var items = await SQLiteHelper.Instance.TableAsync<ProfileItem>() | ||
| .Where(it => idList.Contains(it.IndexId)) | ||
| .ToListAsync(); | ||
| var itemMap = items.ToDictionary(it => it.IndexId); | ||
|
|
||
| return idList.Select(id => itemMap.GetValueOrDefault(id)) | ||
| .Where(item => item != null) | ||
| .ToList(); |
There was a problem hiding this comment.
GetProfileItemsOrderedByIndexIds calls Distinct() on the incoming indexIds, which removes duplicate ids. Previously, call sites that built ordered lists (e.g., group ChildItems ordering) would preserve duplicates by iterating the original id list. If duplicates are meaningful (e.g., weighting / repeated nodes), this changes behavior; consider keeping the original idList for ordering and using a separate distinct set only for the DB query.
There was a problem hiding this comment.
并且这玩意也不是严格对应的,会跳过某些无效项,也不应该直接下标访问,注释没写
There was a problem hiding this comment.
但是是否存在一个可能,用户是故意添加的重复的呢?
先不管了吧,重复的没什么意义,有人说了再改吧
| public async Task<List<ProfileItem>> GetProfileItemsOrderedByIndexIds(IEnumerable<string> indexIds) | ||
| { | ||
| var idList = indexIds.Where(id => !id.IsNullOrEmpty()).Distinct().ToList(); | ||
| if (idList.Count == 0) | ||
| { |
There was a problem hiding this comment.
The method signature takes IEnumerable<string> indexIds, but several new call sites pass Select(sp => sp?.IndexId) which is naturally an IEnumerable<string?> and can contain nulls. Since the implementation already filters out null/empty ids, consider changing the parameter type to IEnumerable<string?> (or accepting nullable and guarding) to better reflect actual usage and avoid nullability mismatches.
| var itemMap = items.ToDictionary(it => it.IndexId); | ||
|
|
||
| return idList.Select(id => itemMap.GetValueOrDefault(id)) | ||
| .Where(item => item != null) |
There was a problem hiding this comment.
idList.Select(id => itemMap.GetValueOrDefault(id)).Where(item => item != null).ToList() relies on a null-filter to satisfy the List<ProfileItem> return type. To keep the non-null contract explicit (and resilient if nullable analysis is enabled later), consider using OfType<ProfileItem>() or null-forgiving after the filter so the resulting list is statically non-nullable.
| .Where(item => item != null) | |
| .OfType<ProfileItem>() |
There was a problem hiding this comment.
这个刚开始的写法就是 .OfType<ProfileItem>() 来着,ReSharper 直接冒绿光让我改成 .Where(item => item != null)