cphilpot
cphilpot

Reputation: 1225

Why is getting roles when getting a list of users so slow?

I'm getting all users in the DB and their associated roles. It works, but man is it slow.

        var ctx = new SiteUserContext();
        var ctxUserList = ctx.Users.ToList();


        //var userManager = new UserManager<SiteUser>(new UserStore<SiteUser>(new SiteUserContext()));

        var jsonModels = from user in ctxUserList
                         select new
                         {
                             userName = user.UserName,
                             Roles = (from userRole in user.Roles
                                      join role in ctx.Roles on userRole.RoleId
                                      equals role.Id
                                      select role.Name).ToList(),
                             id = user.Id
                         };

Getting just a list of users is fine, about 600ms for 100 users. But as soon as I try and add in the roles, I end up waiting 5-10 seconds. Each user only has 1 or 2 roles. This isn't exactly a huge query.

I tried using the userManager GetRolesById(user.Id) but that was even slower. 10+ seconds.

Any tips on making this run quickly would be greatly appreciated.

Upvotes: 2

Views: 466

Answers (1)

Mitchel Sellers
Mitchel Sellers

Reputation: 63126

What you have here is executing N+1 queries to get the information since you get the list of users, then enumerate the list of users to streamline. Using LINQ we can do this a bit more efficiently. I've used this before to do this in one process.

var usersWithRoles = (from user in ctx.Users  
                      select new  
                       {  
                        UserId = user.Id,                                        
                        Username = user.UserName,  
                        Email = user.Email,  
                        RoleNames = (from userRole in user.Roles  
                                     join role in context.Roles on userRole.RoleId   
                                     equals role.Id  
                                     select role.Name).ToList()  
                                  })
                    .ToList()
                    .Select(p => new   
                    {  
                       UserId = p.UserId,  
                       Username = p.Username,  
                       Email = p.Email,  
                       Role = string.Join(",", p.RoleNames)  
                    });  

This should be much faster and get it with 1 query!

Edit: Looking at your request, if you just want the roles as a list, you can skip the second projection from this example. (I had a need to display this in a list, thus the string.Join in the example.

Upvotes: 2

Related Questions