在 Entity Framework Core 中使用 group by 抛出异常连接多个表

Joining multiple tables with group by throws exception in Entity Framework Core

我正在开发一个带有 Entity Framework Core 的项目。我正在使用代码优先方法。我有以下实体。

账户

public class Account
    {
        public Account()
        {
            Id = 0;
            IsActive = true;
            AccountRoles = new List<AccountRole>();
        }

        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public string Mobile { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public DateTime? LastLogin { get; set; }
        public bool IsActive { get; set; }
        public bool? IsSystemAdmin { get; set; }        
        public string PhotoUrl { get; set; }
        public DateTime? CreateDate { get; set; }        
        public int? OrgId { get; set; }

        public IList<AccountRole> AccountRoles { get; set; }

        [NotMapped]
        public string UserFullName
        {
            get
            {
                return $"{FirstName} {LastName}";
            }
        }
    }

角色

public class Role
    {
        public Role()
        {
            Id = 0;
            IsActive = true;
            AccountRoles = new List<AccountRole>();
        }

        public int Id { get; set; }
        public string Title { get; set; }
        public bool? IsActive { get; set; }
        public int? OrgId { get; set; }   
        public IList<AccountRole> AccountRoles { get; set; }
    }

账户角色 public class 帐户角色 { public 帐户角色() { 编号 = 0; IsActive = 真; }

        public int Id { get; set; }
        public int AccountId { get; set; }
        public int RoleId { get; set; }        
        public bool IsActive { get; set; }

        public Account Account { get; set; }
        public Role Role { get; set; }
    }

现在我已经编写了一个 LINQ 查询来加入和分组,以获取所有帐户信息的结果,角色以逗号分隔。查询如下:

var userAccount = (from account in _db.Accounts
                                   join accountRole in _db.AccountRoles on account.Id equals accountRole.AccountId into ars
                                   from ar in ars.DefaultIfEmpty()
                                   join role in _db.Roles on ar.RoleId equals role.Id
                                   where
                                      account.UserName == username
                                     && account.Password == password
                                   group new { account, role } by new
                                   {
                                       account.Id,
                                       account.FirstName,
                                       account.LastName,
                                       account.Email,
                                       account.Mobile,
                                       account.UserName,                                       
                                       account.PhotoUrl
                                   } into ag
                                   select new UserAccountInfo
                                   {
                                       AccountId = ag.Key.Id,
                                       FirstName = ag.Key.FirstName,
                                       LastName = ag.Key.LastName,
                                       Email = ag.Key.Email,
                                       Mobile = ag.Key.Mobile,
                                       Username = ag.Key.UserName,                                       
                                       PhotoUrl = ag.Key.PhotoUrl,
                                       Roles = string.Join(",", ag.Select(x => x.role.Title))
                                   }).FirstOrDefault();

通过 Postman 调用 API 时,我发现了以下错误。谁能帮我解决问题。

System.InvalidOperationException: Processing of the LINQ expression 'GroupByShaperExpression: KeySelector: new { Id = a.Id, FirstName = a.FirstName, LastName = a.LastName, Email = a.Email, Mobile = a.Mobile, UserName = a.UserName, PhotoUrl = a.PhotoUrl }, ElementSelector:new { account = EntityShaperExpression: EntityType: Account ValueBufferExpression: ProjectionBindingExpression: account IsNullable: False , role = EntityShaperExpression: EntityType: Role ValueBufferExpression: ProjectionBindingExpression: role IsNullable: True } ' by 'RelationalProjectionBindingExpressionVisitor' failed. This may indicate either a bug or a limitation in Entity Framework. See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information. at CashFlow.Services.AccountService.ValidateLoginAsync(String username, String password) in D:\Workspace\My Projects\CashFlow\CashFlow-API\SourceCode\Libraries\Services\AccountService.cs:line 77 at Web.Controllers.AccountController.Login(LoginModel model) in D:\Workspace\My Projects\CashFlow\CashFlow-API\SourceCode\Web\Controllers\AccountController.cs:line 51 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

我用下面的方式编写了查询,它工作正常。

var userAccount = (from account in _db.Accounts
                                   join accountRole in _db.AccountRoles on account.Id equals accountRole.AccountId into ars
                                   from ar in ars.DefaultIfEmpty()
                                   join role in _db.Roles on ar.RoleId equals role.Id
                                   where account.UserName == username && account.Password == password
                                   select new UserAccountInfo
                                   {
                                       AccountId = account.Id,
                                       FirstName = account.FirstName,
                                       LastName = account.LastName,
                                       Email = account.Email,
                                       Mobile = account.Mobile,
                                       Username = account.UserName,
                                       PhotoUrl = account.PhotoUrl,
                                       IsActive = account.IsActive,
                                       Roles = role.Title
                                   }).ToList().GroupBy(x => new
                                   {
                                       x.AccountId,
                                       x.FirstName,
                                       x.LastName,
                                       x.Email,
                                       x.Mobile,
                                       x.Username,
                                       x.PhotoUrl,
                                       x.IsActive
                                   }).Select(y => new UserAccountInfo
                                   {
                                       AccountId = y.Key.AccountId,
                                       FirstName = y.Key.FirstName,
                                       LastName = y.Key.LastName,
                                       Email = y.Key.Email,
                                       Mobile = y.Key.Mobile,
                                       Username = y.Key.Username,
                                       PhotoUrl = y.Key.PhotoUrl,
                                       IsActive = y.Key.IsActive,
                                       Roles = string.Join(",", y.Select(a => a.Roles))
                                   });