多表关联筛选子行:如何获取指定角色的屏幕及未勾选子屏幕
问题排查与修正方案
咱们先把你的需求再明确一遍:要找出两类**活跃(IsActive=true)**的屏幕:
- 和给定RoleID列表直接关联的屏幕(也就是这个屏幕在RoleScreen表里有对应记录,且关联的RoleID在listUserRoleIDs里);
- 满足这些条件的子屏幕:IsCheck是false、自己没在RoleScreen表里关联任何角色、而且父屏幕属于第一类(父屏幕被给定的RoleID列表关联)。
你的原有代码逻辑有几个明显的问题:
- 第二个条件里用
x.RoleScreens.Any(...)完全搞错了对象——你要查的是父屏幕的关联情况,不是当前屏幕的; - 漏掉了「当前子屏幕未在RoleScreen表中存在」这个核心判断;
- 把屏幕自身的
IsCheck==false放在了Any的lambda里面,这会导致逻辑判断范围出错,应该先筛出IsCheck=false的屏幕,再判断其他条件。
修正后的代码
// 先把所有被目标角色关联的屏幕ID查出来,这样后续判断更高效 var relatedScreenIds = this.context.RoleScreens .Where(rs => listUserRoleIDs.Contains(rs.RoleID)) .Select(rs => rs.ScreenID) .ToList(); // 筛选符合要求的活跃屏幕 var targetScreens = this.context.Screens .Where(x => x.IsActive) .Where(x => // 第一类:直接和目标角色关联的屏幕 relatedScreenIds.Contains(x.ID) || // 第二类:IsCheck=false的子屏幕,自身无角色关联,且父屏幕属于第一类 (x.IsCheck == false && x.ParentID != null && relatedScreenIds.Contains(x.ParentID.Value) && !x.RoleScreens.Any()) ) .ToList();
为啥这么改?
- 先预查
relatedScreenIds:把所有被目标角色关联的屏幕ID存起来,避免嵌套查询重复计算,性能更好; - 第一个条件直接判断当前屏幕ID在不在
relatedScreenIds里,精准对应第一类需求; - 第二个条件把所有要求都明确列出来:
- 首先是IsCheck=false;
- 必须是子屏幕(ParentID不为空);
- 父屏幕得是被目标角色关联的;
- 自己没有任何RoleScreen记录(也就是没被任何角色关联过)。
如果你的第二类需求其实不需要父屏幕属于角色关联集合,只是单纯要「IsCheck=false、没在RoleScreen里、是子屏幕、活跃」的屏幕,那把第二个条件简化成这样就行:
(x.IsCheck == false && x.ParentID != null && !x.RoleScreens.Any())
内容的提问来源于stack exchange,提问作者user2517610
相关产品推荐
相关产品推荐

