Linq分组后直接选Key报错,分步操作正常,求原因及替代实现
这确实是个有点让人摸不着头脑的问题,我来帮你拆解清楚:
为什么直接分组后Select会报错,存变量就可行?
这大概率是编译器类型推断的小坑。当你把分组后的查询结果赋值给变量pureUsers时,编译器能明确推断出它的类型是IQueryable<IGrouping<string, int>>(假设你的SAPID是string类型、UserRoleID是int类型),此时调用Select(x => x.Key)时,x的类型是IGrouping,自然能找到Key属性。
但当你直接在查询表达式后面追加.Select(),或者在查询表达式内部直接写select g.Key时,编译器可能因为查询表达式的语法解析优先级,错误地把g推断为分组的键类型(也就是string),而非IGrouping<string, int>对象——这就导致了“string不包含Key定义”的报错。
解决分组后直接Select的问题
如果你一定要保留分组的写法,除了先存变量之外,还可以通过显式指定类型修正编译器的推断:
var pureUsers = from u in userContext.Users join ur in userContext.UserRoles on u.UserID equals ur.UserID join r in userContext.Roles on ur.RoleID equals r.RoleID join sm in userContext.SystemMasters on r.SystemMasterID equals sm.SystemMasterID where sm.SystemName == "PURE" group ur.UserRoleID by u.SAPID into g select ((IGrouping<string, int>)g).Key;
或者改用完全链式的写法(避开查询表达式的解析问题):
var pureUsers = userContext.Users .Join(userContext.UserRoles, u => u.UserID, ur => ur.UserID, (u, ur) => new { u, ur }) .Join(userContext.Roles, x => x.ur.RoleID, r => r.RoleID, (x, r) => new { x.u, r }) .Join(userContext.SystemMasters, x => x.r.SystemMasterID, sm => sm.SystemMasterID, (x, sm) => new { x.u, sm }) .Where(x => x.sm.SystemName == "PURE") .GroupBy(x => x.u.SAPID) .Select(g => g.Key);
更高效的去重方案(无需GroupBy)
其实你的核心需求是获取每个SAPID仅出现一次的列表,完全没必要用GroupBy——GroupBy是用来分组聚合数据的,单纯去重用Distinct()更直接高效:
var pureUsers = from u in userContext.Users join ur in userContext.UserRoles on u.UserID equals ur.UserID join r in userContext.Roles on ur.RoleID equals r.RoleID join sm in userContext.SystemMasters on r.SystemMasterID equals sm.SystemMasterID where sm.SystemName == "PURE" select u.SAPID into distinctSapIds select distinctSapIds;
或者更简洁的链式写法:
var pureUsers = userContext.Users .Join(userContext.UserRoles, u => u.UserID, ur => ur.UserID, (u, ur) => new { u, ur }) .Join(userContext.Roles, x => x.ur.RoleID, r => r.RoleID, (x, r) => new { x.u, r }) .Join(userContext.SystemMasters, x => x.r.SystemMasterID, sm => sm.SystemMasterID, (x, sm) => new { x.u, sm }) .Where(x => x.sm.SystemName == "PURE") .Select(x => x.u.SAPID) .Distinct();
这种写法不仅代码更简洁,EF还能生成更高效的SQL查询(通常是SELECT DISTINCT语句),完美匹配你的去重需求。
内容的提问来源于stack exchange,提问作者bobpal
相关产品推荐
相关产品推荐

