Search code examples
c#asp.net-core-identityasp.net-core-2.2

How to sort User and Role in core Identity


I'm trying to display a list of Roles with users in my view.

This is my current output:

Role | Email

A | [email protected]

B | [email protected]

B | [email protected]

C | [email protected]

But I want it to be like this:

Role | Email

A | [email protected]

B | [email protected] <--order by Role, then Email

B | [email protected]

C | [email protected]

Any idea how to order the child in collection?

SettingController.cs

    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;

    public SettingController(UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager)
    {
        _userManager = userManager;
        _roleManager = roleManager;
    }

    public IActionResult Index()
    {
        var usersWithRole = _roleManager.Roles.Include(r => r.UserRoles).ThenInclude(u => u.User).OrderBy(r => r.Name).ToList();

        return View(usersWithRole);
    }

Index.cshtml

@{
    ViewData["Title"] = "Index";
    ViewData["Name"] = "Index";
    int count = 1;
}
<table class="table table-striped bg-white">
    <thead>
        <tr>
            <th>No</th>
            <th>Role</th>
            <th>Email</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var role in Model)
        {
            var result = role.UserRoles;
            @foreach(var userRole in result)
            {
                <tr>
                    <td>@count</td>
                    <td>@role.Name</td>
                    <td>@userRole.User</td>
                </tr>
                count++;
            }   
        }
    </tbody>
</table>

ApplicationRole.cs

public class ApplicationUser : IdentityUser
{
    public ICollection<ApplicationUserRole> UserRoles { get; set; }
}

ApplicationUserRole.cs

public class ApplicationUserRole : IdentityUserRole<string>
{
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
}

ApplicationUser.cs

public class ApplicationUser : IdentityUser
{
    public ICollection<ApplicationUserRole> UserRoles { get; set; }
}

ApplicationDbContext.cs

protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<ApplicationUserRole>(userRole =>
        {
            userRole.HasKey(ur => new { ur.UserId, ur.RoleId });

            userRole.HasOne(ur => ur.Role)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();

            userRole.HasOne(ur => ur.User)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });
    }

Solution

  • I manage to find a way to get the result that I wanted.

    I create entities for the tables and access it via linq instead of using Identity's UserManager and RoleManager.

    Then, I bind the result to ViewModel and display it in my view.

    Controller

    public IActionResult Index()
        {
    
            //var usersWithRole = _roleManager.Roles.Include(r => r.UserRoles).ThenInclude(u => u.User).OrderBy(r => r.Id).ToList();
    
            var roleAndUsers = (from r in _context.Role
                         join ur in _context.UserRole
                         on r.Id equals ur.RoleId
                         join u in _context.User
                         on ur.UserId equals u.Id
                         orderby r.Name, u.Email
                         select new UserAndRoleViewModel { Name = r.Name, Email = u.Email, Id = u.Id }).ToList();
    
            return View(roleAndUsers);
        }
    

    ViewModel

    public class UserAndRoleViewModel
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Id { get; set; }
    }
    

    View

    @{
        ViewData["Title"] = "Index";
        int count=1;
    }
    <table class="table table-striped bg-white">
        <thead>
            <tr>
                <th>No</th>
                <th>Role</th>
                <th>Email</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var role in Model)
            {
                <tr>
                    <td>@count</td>
                    <td>@role.Name</td>
                    <td>@role.Email</td>
                </tr>
                count++;
            }
        </tbody>
    </table>
    

    ApplicationDbContext

        public DbSet<ApplicationRole> Role { get; set; }
        public DbSet<ApplicationUserRole> UserRole { get; set; }
        public DbSet<ApplicationUser> User { get; set; }