I am working on a server side processing datatable which gets about 1000 fake/generic users data from the database and loads 10 rows per page. The way I have written my code right now, it takes at least 2 minutes just to show the first 10 rows.
I have debugged it to find the reason it is taking so long is because I am getting the Roles for each user and showing it on the datatable. When I comment out the getting the roles part and use an empty string and List, the datatable loads fast. But I have to get the Roles and I having a hard time to figure out how to do it. Can someone please help me out in this matter? I have been struggling with the SQL part for the longest time and no success so far.
What I have tried:
private async Task<IEnumerable<UserViewModel>> GetUserData(ApplicationDbContext db)
{
var users = db.Users;
var list = await GetUsers(db, users);
var vmlist = list.Select(item => new UserViewModel()
{
ID = item.ID,
Username = item.Username,
FirstName = item.FirstName,
LastName = item.LastName,
Email = item.Email,
TaxID = item.TaxID,
TaxIdHash = item.TaxIdHash,
IV = item.IV,
TaxIDEncrypted = item.TaxIDEncrypted,
RoleList = RoleRepository.GetRolesByUserId(UserManager, item.ID, false),
Roles = string.Join(",", RoleRepository.GetRolesByUserId(UserManager, item.ID, false).ToArray()),
});
return vmlist;
}
I am calling the GetUserData method in this UserGrid method.
public async Task<ActionResult> UserGrid(DataTablesViewModel param)
{
using (var db = new Infrastructure.Data.ApplicationDbContext())
{
db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
var data = await GetUserData(db);
IQueryable<UserViewModel> filteredUsers = data.AsQueryable();
List<UserViewModel> displayedTasks = filteredUsers.Skip(param.iDisplayStart).Take(param.iDisplayLength).ToList();
int count = filteredUsers.Count();
foreach (var item in displayedTasks){
if (!String.IsNullOrEmpty(item.TaxID) && item.IV != null && item.TaxIDEncrypted != null)
{
if (item.RoleList.Any(x => x == UserRoles.Applicant))
{
string ssndecrypt = GenericHelper.DecryptPortalTaxID(item.IV, item.TaxIDEncrypted);
string ssn = (ssndecrypt.Length == 11 ? ssndecrypt.Substring(7, 4) : ssndecrypt);
item.TaxID = (ssndecrypt.Length == 11 ? String.Join("", item.TaxID.Substring(0, 7), ssn) : ssn);}
}
else
{
item.TaxID = String.Empty;
}
item.Delete = item.RoleList.Intersect(UserRoles.CanDelete).Count() > 0 ?
"<a class=\"delete\" data-url=\"" + Url.Action("DeleteUser", "Users") + "\" data-userid=\"" + item.ID + "\"data-username=\"" + item.Username + "\" href=\"#\">Delete User</a>"
: String.Empty;
}
var result = GridHelper.GetData(displayedTasks);
var json = Json(new
{
sEcho = param.sEcho,
iTotalRecords = count,
iTotalDisplayRecords = count,
aaData = result
},
JsonRequestBehavior.AllowGet);
return await Task.FromResult(json);
}
I will need the RoleList because I use it later for decrypting the encrypted SSN and showing its last 4 numbers.
This is the UserViewModel if needed.
public UserViewModel(IList<string> roles, ApplicationUser user)
{
ID = user.Id;
Username = user.UserName;
Email = user.Email;
RoleList = roles.ToList(); ;
Roles = string.Join(",", RoleList.ToArray());
IsActive = user.IsActive;
AllowRoleChanges = !RoleList.Intersect(UserRoles.FinalConsumers).Any();
AssignableRoles = HousingServices.Core.Models.UserRoles.CanCreate.Select(x => new SelectListItem { Text = x, Value = x }).ToList();
if (RoleList.Contains(UserRoles.Caseworker))
{
AssignableRoles.Add(new SelectListItem { Value = UserRoles.Caseworker, Text = UserRoles.Caseworker });
}
RoleIDs = RoleList.Select(x => x).ToList();
..........
}
}
private async Task<IEnumerable<dynamic>> GetUsers(ApplicationDbContext db, IDbSet<ApplicationUser> users)
{
IQueryable<ApplicationUser> userlist = users;
<pre>var hsuserlist = userlist.Join(db.EliteHousingServicesUsers, u => u.Id, hu => hu.UserId, (u, hu) => new
{
ID = u.Id,
Username = u.UserName,
FirstName = hu.FirstName,
LastName = hu.LastName,
Email = u.Email,
TaxID = "XXX-XX-XXXX",
Active = (u.IsActive ? "Yes" : "No"),
TaxIdHash = hu.TaxIDHash,
IV = hu.IV,
TaxIDEncrypted = hu.TaxIDEncrypted,
IsActive = u.IsActive,
Status = (u.AccessFailedCount >= MaxFailedAccessAttemptsBeforeLockout ?
"<a class=\"unlock\" data-url=\"" + unlockUrl + "\" data-userid=\"" + u.Id + "\"data-username=\"" + u.UserName + "\" href=\"#\">Unlock</a>"
: "<a class=\"reset\" data-url=\"" + resetUrl + "\" data-userid=\"" + u.Id + "\"data-username=\"" + u.UserName + "\" href=\"#\">Reset Password</a>"),
});