使用Group by时无法翻译LINQ表达式



我有一个使用EF core DB优先方法的Asp.net核心web API。在我的SQL server数据库中有以下表:

  • 应用程序表-包含应用程序列表。
  • 角色表—包含角色列表(用户、管理员、超级管理员等)
  • 用户表-包含用户列表
  • 用户角色表—包含用户和角色表
  • 之间的映射
  • 功能表-包含功能列表(主页,用户管理等)
  • RoleFeature表—包含Feature和Role表之间的映射

我正试图获得给定UserId和appId的RoleName和功能列表。

下面是我目前为止的Linq查询:

RoleDto role = 
from a in ctx.Application.Where(x => x.ApplicationId == appId)
from r in ctx.Role.Where(x => x.ApplicationId == a.ApplicationId)
from ur in ctx.UserRole.Where(x => x.UserId == userId && x.RoleId == r.RoleId)
from rf in ctx.RoleFeature.Where(x => x.RoleId == ur.RoleId)
from f in ctx.Feature.Where(x => x.FeatureId == rf.FeatureId).Where(x => x.IsActive)
group new { r.RoleName, f.FeatureId } by ur.RoleId into g
select new RoleDto
{
Name = g.Select(x => x.RoleName).FirstOrDefault(),
FeatureIds = g.Select(x => x.FeatureId).ToList()
}.AsNoTracking()

然而,我得到一个错误说无法翻译LINQ表达式。

问题在于FirstOrDefault()在"groupby"查询。

您可能使用的是高于2.1的ef core版本,并且在处理groupby查询方面有一些变化。你应该看看下面的链接:

https://learn.microsoft.com/en us/ef/core/what - - new/ef核心- 2.1 # linq-groupby-translation

2.1版本之前,在EF Core中GroupBy LINQ操作符总是在内存中求值。我们现在支持将其转换为SQL GROUPBY子句

所以查询应该被转换为SQL GROUP BY,但是像FirstOrDefault()这样的方法不能被转换。作为一个快速的解决方案,您可以将FirstOrDefault()更改为Max(), Min()或其他DB支持的聚合函数。

  1. 您不需要选择Application。您可以直接选择Role作为-
from r in dbCtx.Role.Where(x => x.ApplicationId == appId)

这将简化EF生成的最终SQL。因此,查询将更快。

  1. 如果一个User有多个Role,那么你正试图采取第一个。当你选择Role为-
  2. 时,你应该这样做
from r in ctx.Role.Where(x => x.ApplicationId == a.ApplicationId).Take(1)
  1. 最后,您可以获取RoleNameFeatureId的列表,然后在客户端进行分组-
var query =
from r in dbCtx.Role.Where(x => x.ApplicationId == appId).Take(1)
from ur in dbCtx.UserRole.Where(x => x.UserId == userId && x.RoleId == r.RoleId)
from rf in dbCtx.RoleFeature.Where(x => x.RoleId == ur.RoleId && x.Feature.IsActive)
select new
{
RoleName = rf.Role.RoleName,
FeatureId = rf.FeatureId
};
var roleDto = query.AsNoTracking()
.AsEnumerable()
.GroupBy(p => p.RoleName)
.Select(g => new RoleDto
{
Name = g.Key,
FeatureIds = g.Select(p => p.FeatureId).ToList()
})
.FirstOrDefault();

最新更新