LINQ查询中实现按优先级匹配ConfigurationName的同ID记录筛选
实现方案
实现思路
不用拆成三次串行查库,单条查询就能搞定优先级逻辑:给每条匹配的记录打个优先级标记,按标记排序后按GameObject分组,每组取优先级最高的那条就行,顺便能修掉原代码里的空引用bug。
优先级标记按规则设值(数值越小优先级越高):
- 匹配到
ConfigurationName == draftName:标记0(最高) - 匹配到
ConfigurationName == customName:标记1(次高) - 匹配到
ConfigurationName == null:标记2(最低)
可直接运行的示例代码
string customName = "Config1"; string draftName = "Draft_" + id; var list = db.JoinedGameObjects // 先锁定当前上传ID下的所有关联记录 .Where(x => x.TBUploads_ID == id) // 给每条记录计算优先级 .Select(x => new { Record = x, Priority = x.ConfigurationName == draftName ? 0 : x.ConfigurationName == customName ? 1 : x.ConfigurationName == null ? 2 : 100 }) // 只保留符合三个匹配条件的记录 .Where(x => x.Priority < 100) // 按GameObject的唯一标识分组,实际使用时替换为业务上的GameObject主键即可 .GroupBy(x => x.Record.GameObjectName) // 每个分组取优先级最高的一条记录 .Select(group => group.OrderBy(x => x.Priority).First()) // 映射为需要的ViewModel结构 .Select(x => new GameObjectViewModel() { ID = x.Record.ID, GameObjectName = x.Record.GameObjectName, Category = x.Record.Category, Family = x.Record.Family, Type = x.Record.Type, MetaTypeJson = x.Record.MetaTypeJson, MaterialsJson = x.Record.MaterialsJson, MetadataVisibilityJson = x.Record.MetadataVisibilityJson, Visible = x.Record.joined_Visible ?? x.Record.Visible }) .ToList();
注意事项
- 原代码中写的
x.ConfigurationName.Equals(customName)存在隐患:遇到ConfigurationName为null的记录会直接抛出空引用异常,上述写法把常量放前面做等值判断,可完全规避这个问题 - 所有筛选、排序、分组逻辑都在数据库端执行,不会把全量关联数据拉到内存里处理,性能优于拆成三次单独查库的实现
- 如果你使用的EF版本对
GroupBy支持有限,可直接把优先级逻辑写到OrderBy子句中,实现效果完全一致:
var list = db.JoinedGameObjects .Where(x => x.TBUploads_ID == id && (x.ConfigurationName == draftName || x.ConfigurationName == customName || x.ConfigurationName == null)) .OrderBy(x => x.ConfigurationName == draftName ? 0 : x.ConfigurationName == customName ? 1 : 2) .GroupBy(x => x.GameObjectName) .Select(g => g.First()) .Select(x => new GameObjectViewModel() { // 字段映射逻辑和之前的写法保持一致 }) .ToList();
内容的提问来源于stack exchange,提问作者Cédric Kamermans
相关产品推荐
相关产品推荐

