EF Core 5.0 LINQ表达式无法翻译:First()投影查询通用解法问询
问题本质
报错的核心原因是:预先加载到内存的ur集合属于本地内存对象,EF Core 无法将投影中针对本地集合的First()匹配逻辑翻译为SQL语句,因此会触发客户端评估甚至直接抛出无法翻译的异常。
最优解决方案(推荐)
直接通过EF Core的关联查询逻辑在服务端完成用户和用户角色的匹配,全程在数据库层面执行,无冗余数据加载,性能最优:
// 预加载角色列表生成下拉选项,全局复用无性能问题 var rolesList = await _roleManager.Roles .Select(x => new {x.Id, x.Name}) .ToListAsync(); var appUsers = await _context.Users // 关联UserRoles表完成用户和角色ID的匹配 .Join( _context.UserRoles, user => user.Id, userRole => userRole.UserId, (user, userRole) => new { user, userRole.RoleId } ) .Select(joinResult => new AppUserViewModel { Id = joinResult.user.Id, StaffId = joinResult.user.StaffId, Email = joinResult.user.Email, UserName = joinResult.user.UserName, PhoneNumber = joinResult.user.PhoneNumber, RoleId = joinResult.RoleId, RoleSelectListItems = rolesList.Select(yy => new SelectListItem { Value = yy.Id.ToString(), Text = yy.Name }).ToList() }) .ToListAsync();
备选方案(适用于需要提前加载UserRoles到本地处理的场景)
如果业务逻辑需要先把UserRoles全量加载到内存做其他处理,可以把用户查询和ViewModel映射的逻辑拆分,先全量查完用户数据再在内存做角色匹配,避免EF尝试翻译本地集合操作:
var rolesList = await _roleManager.Roles .Select(x => new {x.Id, x.Name}) .ToListAsync(); // 提前加载UserRoles到内存做其他业务处理 var urList = await _context.UserRoles.ToListAsync(); // 先查询全量用户数据到内存 var users = await _context.Users.ToListAsync(); // 纯内存映射生成ViewModel,无需EF翻译逻辑 var appUsers = users.Select(x => new AppUserViewModel { Id = x.Id, StaffId = x.StaffId, Email = x.Email, UserName = x.UserName, PhoneNumber = x.PhoneNumber, RoleId = urList.First(xu => xu.UserId == x.Id).RoleId, RoleSelectListItems = rolesList.Select(yy => new SelectListItem { Value = yy.Id.ToString(), Text = yy.Name }).ToList() }).ToList();
额外优化建议
如果业务中存在用户未分配角色的场景,建议将First()替换为FirstOrDefault()并增加空值处理逻辑,避免运行时抛出序列不包含任何元素的异常。
内容的提问来源于stack exchange,提问作者NovaDev
相关产品推荐
相关产品推荐

