使用Group by时无法转换LINQ表达式

使用Group by时无法转换LINQ表达式,linq,asp.net-core,entity-framework-core,Linq,Asp.net Core,Entity Framework Core,我有一个Asp.net核心web API,它使用EF core DB first方法。我的SQL server数据库中有以下表格 应用程序表-包含应用程序列表 角色表-包含角色列表(用户、管理员、超级管理员等) 用户表-包含用户列表 用户角色表-包含用户和角色表之间的映射 功能表-包含功能列表(主页、用户管理等) 角色特征表-包含特征和角色表之间的映射 我正在尝试获取给定UserId和appId的角色名和特性列表 以下是我到目前为止的Linq查询: RoleDto role = f

我有一个Asp.net核心web API,它使用EF core DB first方法。我的SQL server数据库中有以下表格

  • 应用程序表-包含应用程序列表
  • 角色表-包含角色列表(用户、管理员、超级管理员等)
  • 用户表-包含用户列表
  • 用户角色表-包含用户和角色表之间的映射
  • 功能表-包含功能列表(主页、用户管理等)
  • 角色特征表-包含特征和角色表之间的映射
我正在尝试获取给定UserId和appId的角色名和特性列表

以下是我到目前为止的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表达式。

问题在于“groupby”查询的select部分中的FirstOrDefault()

您可能正在使用高于2.1的ef核心版本,并且在处理groupby查询时有一些更改。您应该查看以下链接:

在版本2.1之前,在EF Core中,GroupBy LINQ操作符始终 在内存中进行评估。我们现在支持将其转换为SQL组 在最常见的情况下,按条款

因此,应该将查询转换为SQL GROUP BY,但无法转换FirstOrDefault()等方法。作为一种快速解决方案,您可以使用Max()、Min()或DB中支持的其他聚合函数更改FirstOrDefault()

  • 您不需要选择
    应用程序
    。您可以直接选择
    Role
    作为开始-
  • 这将简化EF生成的最终SQL。所以查询速度会更快

  • 如果一个
    用户
    有多个
    角色
    ,那么您将尝试使用第一个角色。当您选择
    Role
    as时,应该这样做-
  • 最后,您可以获取
    RoleName
    FeatureId
    的列表,然后在客户端进行分组-

  • 我试着注释掉语句
    Name=g.Select(x=>x.Name).FirstOrDefault(),
    。我仍然得到同样的错误。我正在使用.net core 3.1 FeatureId呢?你能不能也试着评论一下?我猜问题出在GroupBy上,因为它最近在EfCore中发生了根本性的变化。我认为您只能在groupBy的select部分使用聚合函数。请参阅,并使用
    AsEnumerable
    ToList
    from r in dbCtx.Role.Where(x => x.ApplicationId == appId)
    
    from r in ctx.Role.Where(x => x.ApplicationId == a.ApplicationId).Take(1)
    
    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();