Многогрупповое объединение C # LINQ IdentityContext

#c# #linq #asp.net-identity

#c# #linq #asp.net-идентификатор

Вопрос:

У меня есть этот LINQ:

 var users = _ctx.Users
    .AsEnumerable() // or "InvalidOperationException: This may indicate either a bug or a limitation in EF Core"
    .GroupJoin(_ctx.UserClaims, u => u.Id, c => c.UserId, (user, claims) => new { user, claims })
    .GroupJoin(_ctx.UserRoles, uc => uc.user.Id, r => r.UserId, (uc, roles) => new { uc.user, uc.claims, roles })
    .ToList()
    .Select(ucr => new UserDto
        {
            Id = ucr.user.Id,
            UserName = ucr.user.UserName,
            FirstName = ucr.user.FirstName,
            LastName = ucr.user.LastName,
            LastLogin = ucr.user.LastLogin,
            LockoutEnd = ucr.user.LockoutEnd,
            LockoutEnabled = ucr.user.LockoutEnabled,
            Roles = ucr.roles.Select(x => x.RoleId).Distinct().ToList(), // Here i would like the Role Name from the Roles Table by the UserRoles
            Scopes = ucr.claims.Select(x => x.ToClaim()).Where(x => x.Type.Equals(Shared.Scopes.Key)).Select(x => x.Value).ToList(),
            Claims = ucr.claims.Select(x => x.ToClaim()).Where(x => !x.Type.Equals(Shared.Scopes.Key)).ToList(),
            Enabled = ucr.user.Enabled
    }
).ToList();
  

Это работает отлично, но я хотел бы получить фактические роли для пользователя, а не только сопоставление роли пользователя с ролью из пользовательских ролей

Я попытался добавить дополнительное групповое соединение: .GroupJoin(_ctx.Roles, ucr => ucr.roles.Id, r => r.Id, (ucr, r) => new { u, r }) но поскольку roles это список, я получаю сообщение об ошибке:

‘IEnumerable<IdentityUserRole>’ не содержит определения для ‘Id’ и не имеет доступного метода расширения ‘Id’, принимающего первый аргумент типа ‘IEnumerable<IdentityUserRole>’

Есть идеи, как я могу также получить фактический список ролей?

Я использую классы идентификаторов по умолчанию, отличные от ApplicationUser

     public class ApplicationUser : IdentityUser
    {
        /// <summary>
        /// First Name
        /// </summary>
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        /// <summary>
        /// Last Name
        /// </summary>
        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        /// <summary>
        /// Profile Picture
        /// </summary>
        public byte[] ProfilePicture { get; set; }

        /// <summary>
        /// Enabled
        /// </summary>
        public bool Enabled { get; set; }

        /// <summary>
        /// Last Login
        /// </summary>
        [Display(Name = "Last Login")]
        [DataType(DataType.DateTime)]
        [DisplayFormat(ApplyFormatInEditMode = true, NullDisplayText = "N/A", DataFormatString = "{0:yyyy-MM-dd HH:mm}")]
        public DateTime? LastLogin { get; set; } = null;

        /// <summary>
        /// Display Name
        /// </summary>
        [NotMapped]
        public string DisplayName => $"{FirstName} {LastName}";
    }
  

и UserDTO

 public class UserDto
    {
        public UserDto()
        {
            Id = Guid.NewGuid().ToString();
            ConcurrencyStamp = Guid.NewGuid().ToString();
        }

        public string Id { get; set; }

        public string UserName { get; set; }

        public string NormalizedUserName => UserName.ToUpper();

        public string Email => UserName;

        public string NormalizedEmail => Email.ToUpper();

        public bool EmailConfirmed { get; set; }

        public string PasswordHash { get; set; }

        public string SecurityStamp { get; set; }

        public string ConcurrencyStamp { get; set; }

        public string PhoneNumber { get; set; }

        public bool PhoneNumberConfirmed { get; set; }

        public bool TwoFactorEnabled { get; set; }

        public DateTimeOffset? LockoutEnd { get; set; }

        public bool LockoutEnabled { get; set; }

        public int AccessFailedCount { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public byte[] ProfilePicture { get; set; }

        public DateTime? LastLogin { get; set; }

        public bool Enabled { get; set; }

        public List<string> Roles { get; set; }

        public List<Claim> Claims { get; set; }

        public List<string> Scopes { get; set; }
    }
  

Комментарии:

1. Есть ли шанс, что вы могли бы показать запрос, который не выполняется? А также предоставить полное определение класса для всех задействованных классов?

2. @Enigmativity, я использую классы идентификаторов по умолчанию, которые я добавил ApplicationUser , и дополнительные GroupJoin , которые я пытался добавить.

Ответ №1:

Объединение UserRoles и Roles , поэтому используйте групповое объединение.

      var users = _ctx.Users
        .AsEnumerable()
        .GroupJoin(_ctx.UserClaims, u => u.Id, c => c.UserId, (user, claims) => new { user, claims })
        .GroupJoin(
            _ctx.UserRoles.Join(_ctx.Roles, ur => ur.RoleId, r => r.Id, (userRole, role) => new { userRole, role }),
            uc => uc.user.Id, r => r.userRole.UserId,
            (uc, roles) => new { uc.user, uc.claims, roles})
        .Select(ucr => new
        {
            Id = ucr.user.Id,
            UserName = ucr.user.UserName,
            FirstName = ucr.user.FirstName,
            LastName = ucr.user.LastName,
            LastLogin = ucr.user.LastLogin,
            LockoutEnd = ucr.user.LockoutEnd,
            LockoutEnabled = ucr.user.LockoutEnabled,
            Roles = ucr.roles.Select(x => x.role.Name).Distinct().ToList(),
            Scopes = ucr.claims.Select(x => x.ToClaim()).Where(x => x.Type.Equals(Shared.Scopes.Key)).Select(x => x.Value).ToList(),
            Claims = ucr.claims.Select(x => x.ToClaim()).Where(x => !x.Type.Equals(Shared.Scopes.Key)).ToList(),
            Enabled = ucr.user.Enabled
        }
    ).ToList();
  

Комментарии:

1. Спасибо, я даже не думал, что это возможно! Большое вам спасибо, работает так, как ожидалось.